Talend : Passing values from Parent to Child Job

In the previous post, I discussed automating the Content Migration using Talend. As the power of Talend lies with creating meaningful Jobs which solves a business problem. More often than not, one job has to talk to another job.

Use case:

While working on a migration project, I had a use case where I wanted to pass a value from a Parent Job to a Child Job.

Problem:

globalMap is a useful way to pass values, but it can only be used to pass the values within the same Job. For Instance, If I have a Job A like below:

job1

where tJava_1 is setting a key in globalMap,

globalMap.put("testVal","Test Value 1");

and tJava_2 is trying to retrieve its value.

System.out.println("testVal in the same job is "+(String)globalMap.get("testVal"));

Its value can be retrieved from the components defined in the same Job but if we try to access those values outside this Job, we’ll get the null value.

Solution:

This problem can be solved by utilizing the power of “Context Variables”.Create a Job 2 like as shown below and define a context variable “testValue”

job 3

Create a Job B like as shown below:  (Job 2 is a tRunJob component which is calling the above Job)

job2

Here tJava_1 is setting a key in globalMap,

globalMap.put("testVal","Test Value 1");

To access the above value in Job 2 , define this component’s properties as below. Note the “Context Param” definition, this is how we can set the value in the context variable and retrieve it in the child job.

final job

tJava_1 in Child Job can simply retrieve its value :

System.out.println("testVal in theanother job is "+context.testValue);

Hope it helps !! 🙂

Changing the Port of a Running AEM Instance

AEM derives the port number from the quickstart jar file. As the documentation says that by renaming the jar file, we can configure AEM to run on a different port.

But this requires an instance shutdown. What if we want to change the port number of a running AEM instance? What if it is an e-Commerce site and shutting down the server means the loss of customers which implies the loss of business? This blog post will talk about how to change the port of a running AEM instance.

Use case:

In a production AEM environment, we access the AEM instance through a web server, typically Apache Web Server. Dispatcher module that sits on Apache communicates to the AEM server. An end-user is oblivious to the fact that an AEM server even exists? But if there is a vulnerability in your application which could be exploited through the port it is running on, then a potential hacker can take advantage of it and cause serious security problems by reaching the server through that port.It is always recommended that we should change the default port. Though, it is hidden that which port the AEM server is running on but what if a hacker gets that information? A production system needs to change the port in that case. Changing the port in the usual way requires downtime. And Downtime can have serious impacts.

Resolution:

With AEM 6 onwards, we can change the port of a running AEM instance. Go to Felix Console and search for Apache Felix Jetty Based Http Service.

jetty-service

Change the default value of HTTP Port (highlighted above) with the new port number and hit Save. As soon as you save the configuration, the AEM will start running on the new port. To verify if the configuration works, reload the page. It will not open up. Now, open the same page with the new port specified in the above configuration. You will see that the AEM is running on the new port.

Hope it helps !! 🙂

Creating Custom Node Type in JCR

In this blogpost, I’ll talk about the various ways of creating the Custom Node Type and deploying it across multiple instances. We’ll be using AEM 5.6.1 as our CQ server.

A. Creating and Registering the Custom Nodetype 

There are broadly following three ways of creating custom node types.

  1. Using Node Type Administration console.
  2. Programmatically
  3. Using Package Manager

We’ll discuss them one by one :

  1. Using Node Type Administration Console 
  • Using CND files.

The Compact Namespace and Node Type Definition (CND) notation provides a compact standardized syntax for defining node types and making namespace declarations. The notation is intended both for documentation and for programmatically registering node types. Existing documentation can be followed for creating the CND file.

Go to Node Type Administration console, click on Import  Node Type, copy/paste the CND file in the textarea, keep “Automatically register nodetype” checkbox and “Automatically register defined namespaces” checked. Click on submit and your custom node type will be registered.

  • Without using CND files

Go to Node Type Administration console,click on Create Node Type and enter the details about Node Name , child Node defintions , property definitions , supertypes etc. Click on the [Register Node Type] link at the bottom of the page to register this newly created Node type. Check the nodetype in Node type Administration console.

2. Programmatically

We can register the nodetype programmatically as well.

  • Using CND file.

We can use JCR Commons CndImporter to register it. Following is the code snippet to regsiter it. Create a CND file say nodetypes.cnd having the definition of the new node type. Make this file as a part of the bundle.

  • Without using CND file.

We can use JCR API to create a new node type and register it. Following is the code snippet to register it.


session = slingRepository.loginAdministrative(null); 

NodeTypeManager manager = (NodeTypeManager)session.getWorkspace().
getNodeTypeManager();
NamespaceRegistry ns=session.getWorkspace().getNamespaceRegistry();
ns.registerNamespace("cp","https://codepearlz.wordpress.com/CustomNode");

// Create node type
NodeTypeTemplate nodeTypeTemplate = manager.createNodeTypeTemplate();
nodeTypeTemplate.setName("cp:testNodeType");
// Create a new property PropertyDefinitionTemplate
customProperty1 = manager.createPropertyDefinitionTemplate();
customProperty1.setName("cp:Name");
customProperty1.setRequiredType(PropertyType.STRING); PropertyDefinitionTemplate
customProperty2 = manager.createPropertyDefinitionTemplate();
customProperty2.setName("cp:City");
customProperty2.setRequiredType(PropertyType.STRING);
// Add property to node type
nodeTypeTemplate.getPropertyDefinitionTemplates().add(customProperty1);
nodeTypeTemplate.getPropertyDefinitionTemplates().add(customProperty2);
/* Register node type */
manager.registerNodeType(nodeTypeTemplate, true); session.save();

3. Using Package Manager

We can register node type via package manager as well . In Package Manager, upload a CQ package containing custom nodetypes.cnd  and install it. Check that the custom nodetypes are registered in Node Type Administration console.

Troubleshoot : 

    • After registering the nodetype, make sure it is visible in Node Type Administration console. If not registered, check the error.log for more insight.
    • CND file should be in proper format to avoid unwanted errors.
    • Java 7 introduced a stricter verification and changed the class format a bit — to contain a stack map, used to verify that code is correct. If you are using java 7, pass these parameter -XX:MaxPermSize=512m -Xmx1520m -XX:-UseSplitVerifier while starting the instance from command line. Refer this link for more details.

B. Deploying the Custom Nodetype across multiple instances

If we have enabled clustering, then our multiple author and publish instances will be running on separate machines. We would want the new node type to be visible in all the instances. It can be  done via two ways :

  1. If we are programmatically registering the new node type, then deploying the bundle will simply make it visible across all the instances.
  2. Whenever a new node type gets registered in repository, three files gets updated . custom_nodetypes.xml at <CQ author instance directory>/crx-quickstart/repository/repository/nodetypes  will contain the definition of new node type. ns_idx.properties and ns_reg.properties at <CQ author instance directory>/crx-quickstart/repository/repository/namespaces will have the details of the new namespaces added. Copy/Pasting these files to all the instances at the specified location will make it visible. Note that this will require an instance restart.

Hope it helps !! 🙂

Debugging in AEM

While working on one of a complex requirements in our project, we felt the need to continuously analyze the flow. Though, logs are of good help but we wanted to analyze the complete flow . In this scenario, debugging feature in IDE becomes very handy. Software Stack being used : 

  • CQ Server : AEM 5.6.1
  • IDE : IntelliJIdea 12.0

First We need to start our CQ instance in debug mode. We can do so by starting the AEM in debug mode by running the following command :

 java -jar cq5-author-4502.jar -fork -forkargs -- -Xdebug -Xrunjdwp:transport=dt_socket,address=59865,suspend=n,server=y -Xmx1520m -XX:MaxPermSize=512m -XX:-UseSplitVerifier 

We need to first open the socket from where all the JVM communication will happen. We need to specify the port number while starting the instance. Socket specifies the entry point for all the communication that happens in JVM. Every communication will happen via Socket. In above command, address=59865  is creating the socket for us. In IDE, we need to setup a remote connection for CQ and specify the same port no as mentioned while starting CQ. Follow the below steps to setup a remote connection in IntelliJIdea.

  1. Go to Run panel (top of the window) and select Edit configuration.
  2. Select Defaults and click on “+” to add new configuration. List of all the options will appear. Select “Remote”  from that list.
  3. Enter the details in the window as per your need. Specify the same port number which was used while starting the CQ instance in debug mode.
  4. Click on “OK” to save the configuration.

Below is the screenshot for the reference.

debug

Add breakpoints in the java files which you want to debug by double clicking on the line and start newly created configuration in Debug mode.

Troubleshooting :

1. While starting the AEM instance, make sure JVM has enough heap size for running CQ server, otherwise it will fork the JVM and parameters will not be passed to the forked jvm. Use -fork -forkargs – option to ensure that the command line parameters gets passed to the jvm.

2. If you are using java 7 , make sure to specify the -XX:-UseSplitVerifier parameter to avoid the unwanted strict verification errors while debugging the bundle.

Hope it helps !! 🙂