Article summary

Summary
Discusses how to programmatically retrieve AEM resources from the Java Content Repository (JCR) using Sling APIs. Also discusses how to use the adaptTo method to convert an AEM resource to another type.      
Digital Marketing Solution(s) Adobe Experience Manager (Adobe CQ)
Audience
Developer (intermediate)
Required Skills
Java, Sling, OSGi Maven, HTML
Tested On AEM 5.6, AEM 6.x

Note:

You can download an AEM package that contains code and the OSGi bundle that are used in this article. Download the package and deploy using package manager. The purpose of this code is to show the community these concepts in action. That is, it's to illustrate how to use the Sling API to query AEM resources, such as a page. This community code is for teaching purposes only and not meant to go into production as is.

You can view the sample community application by using the following URL: http://localhost:4502/content/SlingQuery.html (assuming you deploy on author).

Download

Introduction

Adobe Experience Manager contains a Java Content Repository (JCR) that stores nodes and properties. A node located in the JCR is considered a resource. For example, a web page is a resource in the JCR. You can use the JCR API to retrieve resources from the JCR. For information about using the JCR API, see Programmatically Accessing Experience Manager Content using the JCR API

However, you can also retrieve content from the JCR using Sling APIs. In fact, a resource is a central part of Sling and it assumes everything in the JCR is a resource. You can use the Sling API from within an OSGi bundle to retrieve a resource from within the AEM JCR. To use the Sling API from within an OSGi component, you inject an org.apache.sling.api.resource.ResourceResolverFactory instance into the service. See Interface ResourceResolverFactory.

SlingJCR2

 

When using the Sling API to query the AEM JCR, you have access to helper methods that are not available when using the JCR API. For example, the adaptTo method converts a resource into an appropriate object representing a certain aspect of this resource. For example to translate a Resource object to the corresponding Node object, you invoke the adaptTo method:

Node node = resource.adaptTo(Node.class);

This development article guides you through how to build an AEM application that uses the Sling API to retrieve resources from the AEM JCR. An OSGi bundle is created that retrieves a resource, calls the adaptTo method and retrieves a value.  To create an AEM web application that retrieves resources from the JCR by using the Sling API, perform these tasks:

Create an AEM application folder structure 

Create an AEM application folder structure that contains templates, components, and pages by using CRXDE Lite. 

CQAppSetup

 

The following describes each application folder:

  • application name: contains all of the resources that an application uses. The resources can be templates, pages, components, and so on.
  • components: contains components that your application uses. 
  • page: contains page components. A page component is a script such as a JSP file. 
  • global: contains global components that your application uses.
  • template: contains templates on which you base page components. 
  • src: contains source code that comprises an OSGi component (this development article does not create an OSGi bundle using this folder). 
  • install: contains a compiled OSGi bundles container.
To create an AEM application folder structure:
  1. To view the welcome page, enter the URL http://[host name]:[port] into a web browser. For example, http://localhost:4502.
  2. Select CRXDE Lite (if you are using AEM 5.6, click Tools from the left menu). 
  3. Right-click the apps folder (or the parent folder), select Create, Create Folder.
  4. Enter the folder name into the Create Folder dialog box. Enter slingApp
  5. Repeat steps 1-4 for each folder specified in the previous illustration. 
  6. Click the Save All button.

Note:

You have to click the Save All button when working in CRXDE Lite for the changes to be made.  

Create a template

You can create a template by using CRXDE Lite. A template enables you to define a consistent style for the pages in your application. A template comprises of nodes that specify the page structure. For more information about templates, see Templates

To create a template, perform these tasks:

1. Go to CRXDE Lite at http://localhost:4502/crx/de/index.jsp.
2. Right-click the template folder (within your application), select Create, Create
Template.
3. Enter the following information into the Create Template dialog box:

  • Label: The name of the template to create. Enter templateSling
  • Title: The title that is assigned to the template.
  • Description: The description that is assigned to the template.
  • Resource Type: The component's path that is assigned to the template and copied to implementing pages. Enter slingApp/components/page/templateSling.
  • Ranking: The order (ascending) in which this template will appear in relation to other templates. Setting this value to 1 ensures that the template appears first in the list.

4. Add a path to Allowed Paths. Click on the plus sign and enter the following value: /content(/.*)?.
5. Click Next for Allowed Parents.
6. Select OK on Allowed Children.

Create a render component that uses the template

Components are re-usable modules that implement specific application logic to render the content of your web site. You can think of a component as a collection of scripts (for example, JSPs, Java servlets, and so on) that completely realize a specific function. In order to realize this functionality, it is your responsibility as a Experience Manager developer to create scripts that perform specific functionality. For more information about components, see Components.

By default, a component has at least one default script, identical to the name of the component. To create a render component, perform these tasks:

1. Go to CRXDE Lite at http://localhost:4502/crx/de/index.jsp.
2. Right-click /apps/slingApp/components/page, then select
Create, Create Component.
3. Enter the following information into the Create Component dialog box:

  • Label: The name of the component to create. Enter templateSling.
  • Title: The title that is assigned to the component.
  • Description: The description that is assigned to the template.
  • Super Type: foundation/components/page (in AEM 6, you specify this value for page components. In previous versions of AEM, this was not required.)

5. Select OK on Allowed Children.
6. Open the templateSling.jsp located at: /apps/slingApp/components/page/templateSling/templateSling.jsp.
7. Enter the following JSP code.

 

<html>
<head>
<title>Hello World !!!</title>
</head>
<body>
<h1>Hello Sling API!!!</h1>
<h2>This page will retrieve a resource from the AEM JCR using the Sling API</h2>
</body>
</html>

Setup Maven in your development environment 

You can use Maven to build an OSGi bundle that uses the QueryBuilder API and is deployed to Experience Manager. Maven manages required JAR files that a Java project needs in its class path. Instead of searching the Internet trying to find and download third-party JAR files to include in your project’s class path, Maven manages these dependencies for you.

You can download Maven 3 from the following URL:

http://maven.apache.org/download.html

After you download and extract Maven, create an environment variable named M3_HOME. Assign the Maven install location to this environment variable. For example:

C:\Programs\Apache\apache-maven-3.0.4

Set up a system environment variable to reference Maven. To test whether you properly setup Maven, enter the following Maven command into a command prompt:

%M3_HOME%\bin\mvn -version

This command provides Maven and Java install details and resembles the following message:

OS name: "windows 7", version: "6.1", arch: "amd64", family: "windows"

Note:

For more information about setting up Maven and the Home variable, see: Maven in 5 Minutes.

Next, copy the Maven configuration file named settings.xml from [install location]\apache-maven-3.0.4\conf\ to your user profile. For example, C:\Users\scottm\.m2\.

You have to configure your settings.xml file to use Adobe’s public repository. For information, see Adobe Public Maven Repository at http://repo.adobe.com/.

Create an Experience Manager archetype project  

You can create an Experience Manager archetype project by using the Maven archetype plugin. In this example, assume that the working directory is C:\AdobeCQ.  

plugin1

 

To create an archetype project, perform these steps:

1. Open the command prompt and go to your working directory (for example, C:\AdobeCQ).

2. Run the following Maven command:

mvn archetype:generate -DarchetypeRepository=https://repo.adobe.com/nexus/content/groups/public/ -DarchetypeGroupId=com.day.jcr.vault -DarchetypeArtifactId=multimodule-content-package-archetype -DarchetypeVersion=1.0.2 -DgroupId=custom.sling -DartifactId=querysling -Dversion=1.0-SNAPSHOT -Dpackage=custom.sling -DappsFolderName=myproject -DartifactName="My Project" -DcqVersion="5.6.1" -DpackageGroup="My Company"

3. When prompted for additional information, specify Y

4. Once done, you will see a message like:

[INFO] Finished at: Wed Mar 27 13:38:58 EDT 2013
[INFO] Final Memory: 10M/184M

5. Change the command prompt to the generated project. For example: C:\AdobeCQ\querysling. Run the following Maven command:

mvn eclipse:eclipse

After you run this command, you can import the project into Eclipse as discussed in the next section.

Note:

Ensure that Adobe Maven repository is configured in your POM file. You'll need to do that before this goal will work (and the content-package-maven-plugin can be resolved).

Add Java files to the Maven project using Eclipse

To make it easier to work with the Maven generated project, import it into the Eclipse development environment, as shown in the following illustration.

SlingProject


Note:

Delete all Java files in this project. Keep only the Java files listed in this article. 

The next step is to add Java files to the custom.sling package. The Java files that you create in this section use the Sling API to retrieve a resource in the AEM JCR. For information, see Sling API.

Add the following Java files to the package named custom.sling:

  • A Java interface named Query.
  • A Java class named QueryImp that implements the Query interface.

Query interface 

The following code represents the Query interface that contains a method named getJCRData. The implementation logic for this method is located in the QueryImp class. The getJCRData method uses the Sling API to retrieive a resource located in the AEM JCR.

package custom.sling;
 
public interface Query{
     
    public String getJCRData(String location) ;
 
}

QueryImp class

The QueryImp class uses the following Apache Felix SCR annotations to create the OSGi component:

  • @Component - defines the class as a component
  • @Service - defines the service interface that is provided by the component
  • @Reference - injects a service into the component

In this development article, a ResourceResolverFactory instance is injected into the getJCRData method. This instance is required to retrieve a resource from the AEM JCR. To inject a ResourceResolverFactory instance, you use the @Reference annotation to define a class member, as shown in the following example.

//Inject a Sling ResourceResolverFactory
@Reference
private ResourceResolverFactory resolverFactory;

Within the getJCRData method, invoke the ResourceResolverFactory object's getAdministrativeResourceResolver method to create a ResourceResolver object. You can use a ResourceResolver instance to get a resource located in the AEM JCR as shown here.

ResourceResolver resourceResolver = resolverFactory.getAdministrativeResourceResolver(null);
Resource res = resourceResolver.getResource(resourcePath);

Once you have a Resource instance, you can call the adaptTo method that converts (adapt) the resource to another type. For example, assume that the resource is a page (cq:Page). You can create a com.day.cq.wcm.api.Page instance by calling the adaptTo method as shown in the following example.

//Adapt the resource to another type - in this example to a com.day.cq.wcm.api.page
Page page = res.adaptTo(Page.class);
String title = page.getTitle();
 

The following Java code represents the QueryImp class that uses the Sling API.  

package custom.sling;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
 
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import java.io.StringWriter;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
 
import javax.jcr.Repository; 
import javax.jcr.SimpleCredentials; 
import javax.jcr.Node; 
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
  
import org.apache.jackrabbit.commons.JcrUtils;
 
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
 
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import javax.jcr.RepositoryException;
import org.apache.felix.scr.annotations.Reference;
import org.apache.jackrabbit.commons.JcrUtils;
 
import javax.jcr.Session;
import javax.jcr.Node; 


//Sling Imports
import org.apache.sling.api.resource.ResourceResolverFactory ; 
import org.apache.sling.api.resource.ResourceResolver; 
import org.apache.sling.api.resource.Resource; 
import com.day.cq.wcm.api.Page; 

//This is a component so it can provide or consume services
@Component

 
@Service
public class QueryImp implements Query {

//Inject a Sling ResourceResolverFactory
@Reference
private ResourceResolverFactory resolverFactory;
	
@Override
public String getJCRData(String location) {
try
{
    //Get the title of the AEM web page at this specific location - assume its a value such as /content/geometrixx/en/services
     ResourceResolver resourceResolver = resolverFactory.getAdministrativeResourceResolver(null);
     Resource res = resourceResolver.getResource(location);	
	        
    //Adapts the resource to another type - in this example to a     com.day.cq.wcm.api.page
Page page = res.adaptTo(Page.class);
String title = page.getTitle(); // Get the title of the web page
return title ; 
}
catch (Exception e)
{
	e.printStackTrace()  ; 
}
		
return null;
	}

}

Modify the Maven POM file  

Modify the POM files to successfully build the OSGi bundle. In the POM file located at C:\AdobeCQ\querysling\bundle, add the following dependencies.

  • org.apache.felix.scr
  • org.apache.felix.scr.annotations
  • org.apache.jackrabbit
  • org.apache.sling
  • com.day.cq.wcm.api

Because the Sling API is used, a Maven dependency for that API exists.

<dependency>
    <groupId>org.apache.sling</groupId>
    <artifactId>org.apache.sling.api</artifactId>
    <version>2.2.4</version>
    <scope>provided</scope>
  </dependency>

Also because the Java class contains a dependency to the com.day.cq.wcm.api.Page API, you have to add the following <repositories> element to your POM file.

Add the following <repositories> element to your POM file.

<repositories>
    <repository>
    <id>adobe</id>
    <name>Adobe Public Repository</name>
    <url>http://repo.adobe.com/nexus/content/groups/public/</url>
    <layout>default</layout>
    </repository>
    </repositories>
    <pluginRepositories>
    <pluginRepository>
    <id>adobe</id>
    <name>Adobe Public Repository</name>
    <url>http://repo.adobe.com/nexus/content/groups/public/</url>
    <layout>default</layout>
    </pluginRepository>
</pluginRepositories>

Once you add this repository element to your POM file, you can add the following dependency to your POM file, that lets you use the com.day.cq.wcm.api.Page API in your Java code.

<dependency>
<groupId>com.day.cq.wcm</groupId>
<artifactId>cq-wcm-api</artifactId>
<version>5.5.0</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>com.day.cq</groupId>
<artifactId>cq-commons</artifactId>
<version>5.5.0</version>
<scope>provided</scope>
</dependency>

The following XML represents the POM file to build the OSGi bundle that contains the Sling API.  

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd ">
    <modelVersion>4.0.0</modelVersion>
    <!-- ====================================================================== -->
    <!-- P A R E N T P R O J E C T D E S C R I P T I O N -->
    <!-- ====================================================================== -->
    <parent>
        <groupId>custom.sling</groupId>
        <artifactId>querysling</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <!-- ====================================================================== -->
    <!-- P R O J E C T D E S C R I P T I O N -->
    <!-- ====================================================================== -->

    <artifactId>querysling-bundle</artifactId>
    <packaging>bundle</packaging>
    <name>My Project Bundle</name>

   <dependencies>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>org.osgi.compendium</artifactId>
        </dependency>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>org.osgi.core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.felix</groupId>
            <artifactId>org.apache.felix.scr.annotations</artifactId>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </dependency>
         
          
        <dependency>
         <groupId>org.apache.felix</groupId>
   
         <artifactId>org.osgi.core</artifactId>
   
         <version>1.4.0</version>
      </dependency>
         
        
          
    <dependency>
    <groupId>org.apache.jackrabbit</groupId>
    <artifactId>jackrabbit-core</artifactId>
    <version>2.4.3</version>
    </dependency>
       
    <dependency>
    <groupId>org.apache.jackrabbit</groupId>
    <artifactId>jackrabbit-jcr-commons</artifactId>
    <version>2.4.3</version>
    </dependency>
   <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
           
    <dependency>
            <groupId>org.apache.sling</groupId>
            <artifactId>org.apache.sling.api</artifactId>
            <version>2.2.4</version>
            <scope>provided</scope>
        </dependency>
         
      <dependency>
         <groupId>javax.jcr</groupId>
         <artifactId>jcr</artifactId>
         <version>2.0</version>
      </dependency>
       
       <dependency>
            <groupId>com.day.cq.wcm</groupId>
            <artifactId>cq-wcm-api</artifactId>
            <version>5.5.0</version>
            <scope>provided</scope>
        </dependency>
         
        <dependency>
            <groupId>com.day.cq</groupId>
            <artifactId>cq-commons</artifactId>
            <version>5.5.0</version>
            <scope>provided</scope>
        </dependency>
               
    </dependencies>

    <!-- ====================================================================== -->
    <!-- B U I L D D E F I N I T I O N -->
    <!-- ====================================================================== -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-scr-plugin</artifactId>
                <executions>
                    <execution>
                        <id>generate-scr-descriptor</id>
                        <goals>
                            <goal>scr</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>custom.sling.querysling-bundle</Bundle-SymbolicName>
                    </instructions>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.sling</groupId>
                <artifactId>maven-sling-plugin</artifactId>
                <configuration>
                    <slingUrl>http://${crx.host}:${crx.port}/apps/myproject/install</slingUrl>
                    <usePut>true</usePut>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                 <configuration>
                    <excludePackageNames>
                        *.impl
                    </excludePackageNames>
                 </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Build the OSGi bundle using Maven  

To build the OSGi component by using Maven, perform these steps:

  1. Open the command prompt and go to the C:\AdobeCQ\querysling folder.
  2. Run the following maven command: mvn clean install.
  3. The OSGi component can be found in the following folder: C:\AdobeCQ\querysling\bundle\target. The file name of the OSGi component is querysling-bundle-1.0-SNAPSHOT.jar.
     

Deploy the bundle to Experience Manager

Once you deploy the OSGi bundle, you are able to invoke the getJCRData method defined in the QueryImp class (this is shown later in this development article). After you deploy the OSGi bundle, you will be able to see it in the Apache Felix Web Console.

 

felix
Apache Felix Web Console Bundles view

Deploy the OSGi bundle by performing these steps:

  1. Login to Experience Manager’s Apache Felix Web Console at http://server:port/system/console/bundles (default admin user = admin with password= admin).
  2. Click the Bundles tab, sort the bundle list by Id, and note the Id of the last bundle.
  3. Click the Install/Update button.
  4. Browse to the bundle JAR file you just built using Maven. (C:\AdobeCQ\querysling\bundle\target).
  5. Click Install.
  6. Click the Refresh Packages button.
  7. Check the bundle with the highest Id.
  8. Click Active. Your new bundle should now be listed with the status Active.
    If the status is not Active, check the error.log for exceptions.

Modify the render component to invoke getJCRData method  

Modify the templateSling.jsp file to invoke the getJCRData method that is defined by the QueryImpl class that uses the Sling API. The argument of this method is a string value that specifies the location of the JCR content. For example, /content/geometrixx/en/services. 

To invoke this service, you call sling.getService method as shown in the following example.

//create a custom.sling.Query instance
custom.sling.Query wfService = sling.getService(custom.sling.Query.class);

The following code represents the templateSling JSP page.  

<%@include file="/libs/foundation/global.jsp"%>
<%@taglib prefix="cq" uri="http://www.day.com/taglibs/cq/1.0" %>
<h1>TemplateSling Page</h1>
<%
//create a custom.sling.Query instance
custom.sling.Query wfService = sling.getService(custom.sling.Query.class);

%>
<h2>Use the Sling API to get title of the resource at /content/geometrixx/en/service</h2>
 
<h3>The title of the page is: <%=  wfService.getJCRData("/content/geometrixx/en/services")%></h3>

Modify the templateSling JSP file:

1. To view the welcome page, enter the URL: http://[host name]:[port] into a web browser. For example, http://localhost:4502.

2. Select CRXDE Lite.

3. Double-click /apps/slingApp/components/page/templateSling/templateSling.jsp.

4. Replace the JSP code with the new code shown in this section.

5. Click Save All.

Create a web page that displays resource values

The final task is to create a site that contains a page that is based on the templateSling (the template created earlier in this development article). This web page invokes the getJCRData method as shown in the following illustration.  

page

The following illustration shows the resource located in the AEM JCR that was retrieved in this example.  

SlingPic

Create a web page that is based on the templateSling template.

1. Go to the welcome page at http://[host name]:[port]; for example, http://localhost:4502.
Select Websites.

2. From the left hand pane, select Websites.

3. Select New Page.

4. Specify the title of the page in the Title field.

5. Specify the name of the page in the Name field.

6. Select templateSling from the template list that appears. This value represents the template that is created in this development article. If you do not see it, then repeat the steps in this development article. For example, if you made a typing mistake when entering in path information, the template will not show up in the New Page dialog box.

6. Open the new page that you created by double-clicking it in the right pane. The new page opens in a web browser.

 

 

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License  Twitter™ and Facebook posts are not covered under the terms of Creative Commons.

Legal Notices   |   Online Privacy Policy