How to Copy AEM node tree in JCR/CRX

Here i am going to explain how to create a maven project which can be used to connect your Local AEM instance and play with content.

  1. Step1 : Create a maven project structure
  2. Step2: Create a JAVA class that can be used to connect with your local AEM instance
  3. Step3: Update pom.xml file for adding the dependencies and profile.
  4. Step4: Compile/package your code by maven command
  5. Step5: Run your Compiled java class to test the connectivity and the JCR operations of workspace copy.

Step1: Create a maven project structure.

mvn archetype:generate -DgroupId=com.vardhan.mavenexp -DartifactId=mvnjavaexample -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

here i have used a simple maven quickstart archetype to generate a folder structure for my project once i execute the above command it will create the following folder structure.

mavencreate.JPG

folderstructure.JPG

Step2: Create a JAVA class that can be used to connect with your local AEM instance.

you can rename the App.java file to your wish name and place the below code into that new/renamed java file. (Here i have created additional new file named WorkspaceCopyTest.java which contains the below code)

package com.vardhan.mavenexp;

/**
* A simple JCR play Class
*/

import javax.jcr.Repository;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.Node;
import javax.jcr.Workspace;
import org.apache.jackrabbit.commons.JcrUtils;
import org.apache.jackrabbit.core.TransientRepository;
import javax.jcr.NodeIterator;

public class WorkspaceCopy {

public static void main(String[] args) throws Exception {

try {

//Create a connection to the CQ repository running on local host
Repository repository = JcrUtils.getRepository(“http://localhost:4502/crx/server”);

//Create a Session
//javax.jcr.Session session = repository.login( new SimpleCredentials(“admin”, “admin”.toCharArray()));
String WORKSPACE = “crx.default”;
javax.jcr.Session session = repository.login(new SimpleCredentials(“admin”, “admin”.toCharArray()), WORKSPACE);
Workspace workspace = session.getWorkspace();
Node root = session.getRootNode();
// Source and Destination paths
Node srcnodepath = root.getNode(“./content/dam/geometrixx/portraits”);
Node destnode = root.getNode(“./content/dam/geometrixx/test/”);

if (srcnodepath.hasNodes()) {
NodeIterator worknodes = srcnodepath.getNodes();
while (worknodes.hasNext()) {
Node childnde = worknodes.nextNode();
// formation of destination path and its relative path variables
String[] parts = childnde.getPath().split(“/”);
String destrelativepath = parts[((parts.length) – 1)];
String destpath = destnode.getPath() + “/” + parts[((parts.length) – 1)];
// calling validate destination method to verify if destination path already exist then will not create node again.
if (validatedestpath(destnode, destrelativepath)) {
workspace.copy(childnde.getPath(), destpath);
}
}
}
System.out.println(“:::Hurray workspace copy completed:::”);
session.logout();
} catch (Exception e) {
e.printStackTrace();
}
}
static Boolean validatedestpath(Node destnode, String destrelativepath) {
try {
if (destnode.hasNode(destrelativepath)) {
return false;
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
}

 

workspacecopy.JPG

Step3: Update pom.xml file for adding the dependencies and profile.

open the pom.xml file and update it as shown below. here i have added JCR dependencies as well as one profile to call main class in install phase.

<project xmlns=”http://maven.apache.org/POM/4.0.0&#8243; xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221;
xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd”&gt;
<modelVersion>4.0.0</modelVersion>
<groupId>com.vardhan.mavenexp</groupId>
<artifactId>mvnjavaexample</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>mvnjavaexample</name>
<url>http://maven.apache.org</url&gt;
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.jcr</groupId>
<artifactId>jcr</artifactId>
<version>2.0</version>
</dependency>

<!– https://mvnrepository.com/artifact/org.apache.jackrabbit/jackrabbit-jcr-commons –>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-jcr-commons</artifactId>
<version>2.2.0</version>
</dependency>
<!– https://mvnrepository.com/artifact/org.apache.jackrabbit/jackrabbit-core –>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-core</artifactId>
<version>2.14.0</version>
</dependency>
<!– https://mvnrepository.com/artifact/org.apache.jackrabbit/jackrabbit-jcr2dav –>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-jcr2dav</artifactId>
<version>2.14.0</version>
</dependency>

<!– The SFL4J logging implementation you prefer –>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
</dependencies>
<profiles>
<profile>
<id>vardhan-mvnjava</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>com.vardhan.mavenexp.WorkspaceCopy</mainClass>
<arguments>
<argument>arg0</argument>
<argument>arg1</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>

</project>

Step4: Compile/package your code by maven command.

mvn clean package

Use the above command at mvnjavaexample folder where your pom.xml file exists.

it might take some time for the first time build to download the dependencies, make sure you are not behind the proxy else you need to setup your maven to use proxy settings.

buildsuccess.JPG

you can verify in the compiled classes and a jar build with your classes inside target folder.classes.JPG

Step5: Run your Compiled java class to test the connectivity to local instance and the JCR workspace copy operation.

Now its time to run the class and see if our code snippet works fine.

In this code i have taken source path as /content/dam/geometrixx/portraits which contains some images as shown below and destination path as /content/dam/geometrixx/test/ which is an empty folder.

damfolders.JPG

Now lets run the below maven command to call our WorkspaceCopy class and execute the workspace.copy operation between the source path and destination path.

mvn exec:java -Dexec.mainClass=”com.vardhan.mavenexp.WorkspaceCopy

runsuccess.JPG

once you got the success message in your command prompt you should be able to see the nodes got copied to your test folder.

nodecreated.JPG

You can test the code by deleting any nodes under test and re run the above maven command which will recreate the deleted nodes again.

The same class can also be called by using the maven profile created in our pom.xml file with the below command.

mvn install -Pvardhan-mvnjava

The Help sample has been created and executed with below versions of dependencies.

Maven Version: apache-maven-3.1.1
Java version: 1.7.0_45
AEM Version: 6.2

Understand AEM Sling Resource Merger, Override and Overlay concepts

Overlay:

When you overlay a component in AEM means that copy component from /libs/ folder to /apps/.. folder. And you can impose your own definitions(like change title,group,business logic functionalities) on the newly copied components under /apps/..

As per the default OSGI preferences AEM uses a search path to find a resource, searching first the /apps/ branch and then the /libs branch so your newly copied components under /apps/ gets priority than the /libs/.

Note that we can modify search paths and its priority order by changing it from the Felix console Apache Sling Resource Resolver Factory configurations.

You can try overlaying these libs/foundation/components/ list, image, Text&Image, Carousel, etc,. simple components to play around and change the dialogs, jsp level functionalities and see the behaviour. When you are overlaying a component remember that both components can show up in the authors sidekick, For your overlay /apps/.. component , if the title, componentGroups are the same as /libs/.. component, in design mode of the parsys to enable component can distinguish them with parenthesis around the component (foundation) vs (your project).

overlay.png

Override:

You can extend/override Component behaviour by using sling:resourceSuperType property.

Creating a custom component manually by creating all necessary nodes and setting value of sling:superResourceType property to that component will inherit all the feature from /libs/ component, even after upgrade you still inherit the features of image component.

Here we can use the sling:superResourceType for any component that you want to inherit functionality (example from projectA component to ProjectB etc., not only restricted to libs). There is a usage difference for the overlay from AEM 6.0 versions onwards as the new Granite Touch UI has been introduced, have a look at Adobe Documentation

AdobeDocumentation.png

Sling Resource Merger:

Have look at the Sling Resource Merger for understanding the Resource Merger bundle concept. It’s a Sling framework bundle (org.apache.sling.resourcemerger) which gives you flexibility to have merged view on multiple other resources. The exact merging mechanism depends on the resource picker implementation (i.e. Overlay or Override).

By this Sling Resource Merger It is possible to

  1. remove existing resource/properties from the underlying resources,
  2. modify existing properties/child resources of the underlying resources and
  3. add new properties/child resources

The resource merger provides the following properties to achieve the above

  1. sling:hideProperties (String or String[]) — Specifies the property, or list of properties, to hide.The wildcard * hides all.
  2. sling:hideResource (Boolean) — Indicates whether the resources should be completely hidden, including its children.
  3. sling:hideChildren (String or String[]) — Contains the child node, or list of child nodes, to hide. The properties of the node will be maintained. The wildcard * hides all.
  4. sling:orderBefore (String) — Contains the name of the sibling node that the current node should be positioned in front of.

AEM default installation you will have this bundle available the same can be verified from your Felix console with bundle symbolic name org.apache.sling.resourcemerger

The goals for using the Sling Resource Merger in AEM are to:

  1. ensure that customization changes are not made in /libs.
  2. reduce the structure that is replicated from /libs.

Let’s go to an AEM example to implement or utilize it

Currently am going to overlay the Tools related node jcr:title value which is under /libs/ to /apps

Tools.png

componentoverlay.png

componentdialog.png

Now update the jcr:title property alone on the overlay component node property which is under /apps/.. 

updatejcrtitle.png

VerifyJcrTitle.png

Like this you can overlay any component from libs and update the required functionality changes to that particular nodes.

Let’s see one more example usage of sling Resource Merger property

Here as shown above I have overlayed the sites node also along with the jcr:title property I have added the sling:hideProperties as shown below.

slinghideproperty.png

Now look at the output of the sites title in the touch UI page navigation make sure you handle null in presentation layer.

slinghideverify.png

Similar way you can play with other properties as well.

~ Enjoy learning and help others.

Simple DAM Image retrieval Example

  1. Create a component named imageretrieval by right clicking on any project (here am taking a geometrixx-outdoors project as my project)
  2. Create a dialog as shown below node structure.imagedialog.pngimagedialogjson.png
  3. the dialog finally results as shown belowimagepagedialog.png
  4. imageretrieval.jsp code snippet (have added both scriptlet and JSTL way of retrieving)

    <%–
    image retrieval component.
    –%>
    <%
    %><%@include file=”/libs/foundation/global.jsp”%><%
    %><%@page session=”false” %><%
    %>
    <b>::This is simple test to hide/show image from dialog box::</b>

    <!– JSP Scriplet Style of retrieval –>
    <%
    boolean isChecked = properties.get(“showimage”, false);
    String imgpath = properties.get(“imgpath”, “”);
    //out.println(isChecked);
    //out.println(imgpath);
    //write the scriplet code if conditions for retrieval of dialog values and display image in page
    %>

    <!– JSTL code which displays the image based on the dialog selection –>
    </br>
    <c:if test=”${properties.showimage}”>
    <c:if test=”${not empty properties.imgpath}”>
    <img src=’${properties.imgpath}’ alt=”Smiley face” width=”100″ height=”100″>
    </c:if>
    </c:if>

  5. Finally drag and drop the component into any geometrixx-outdoors page and edit the dialog to see the functionality resultimagepage.png