Article summary

Summary
Discusses how to create an AEM application that queries Adobe Experience Manager user information.  
Digital Marketing Solution(s) Adobe Experience Manager (Adobe CQ)
Audience
Developer (intermediate)
Required Skills
JavaScript, AJAX, HTML
Tested On Adobe Experience Manager 5.5, 5.6

Introduction

You can use an AJAX request to retrieve Adobe Experience Manager users and display the result set in a data grid control. To retrieve user data from Experience Manager, you use a com.day.cq.security.UserManager instance that belongs to the Experience Manager API. This API provides access to both users and groups. The following illustration shows Experience Manager users displayed within a grid control. 

UserGrid

This development article guides you through creating this AEM application that retrieves user data and displays the data in a client web page. In addition, the application also adds new users to Experience Manager. To create an Experience Manager web application that queries Experience Manager users and adds users, perform these tasks:

  1. Create an Experience Manager application folder structure. 
  2. Create a template on which the page component is based. 
  3. Create a render component that uses the template. 
  4. Add a data grid plugin to a cq:ClientLibraryFolder node.
  5. Modify the render component to invoke UserManager operations. 
  6. Create a site that contains a page that displays Experience Manager user data.

Create an Experience Manager application folder structure

Create an Experience Manager 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 users
  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. 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 template folder (within your application), select Create, Create Template.

4. Enter the following information into the Create Template dialog box:

  • Label: The name of the template to create. Enter userTemplate.
  • 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 users/components/page/userTemplate.
  • 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.

5. Add a path to Allowed Paths. Click on the plus sign and enter the following value: /content(/.*)?.

6. Click Next for Allowed Parents.

7. 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 an AEM 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. 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 /apps/jcrquery/components/page, then select Create, Create Component.

4. Enter the following information into the Create Component dialog box:

  • Label: The name of the component to create. Enter userTemplate
  • Title: The title that is assigned to the component.
  • Description: The description that is assigned to the template.

5. Select Next for Advanced Component Settings and Allowed Parents.

6. Select OK on Allowed Children.

7. Open the templateQueryjsp located at: /apps/users/components/page/userTemplate/userTemplate.jsp.

8. Enter the following JSP code.

<html>
<head>
<title>Hello World !!!</title>
</head>
<body>
<h1>Hello CQ Users!!!</h1>
<h2>This page will query the CQ users</h2>
</body>
</html>

Add the data grid library to a cq:ClientLibraryFolder node

You add CSS files and JQuery framework files to a cq:ClientLibraryFolder node to define the style of the client JSP. The JQuery framework file that is added is named jquery-1.6.3.min.js.

In addition to the JQuery framework file, a data grid plugin named flexigrid is used. This plugin is used to display Adobe CQ users in a tabular format. Download the flexigrid plugin from the following URL:

http://flexigrid.info/

Note:

You can use other data grid plugins in an AEM application as well. For example, the following AEM article uses another data grid control named DataTables. For information, see Querying Adobe Experience Manager Data using the JCR API.

Download and extract the flexigrid archive file. The AEM application uses these files from the archive file:

  • flexigrid.pack.css
  • flexigrid.pack.js

In addition, copy the images folder to the cq:ClientLibraryFolder node. The following illustration displays the files that you must add to this node.

clientlibs

To add CSS files and JQuery framework files to your component, add a cq:ClientLibraryFolder node to your component. After you create the node, set properties that allow the JSP script to find the CSS files and the JQuery library files. Add these two properties to this node.

Name  Type  Value 
dependencies  String[]  cq.jquery 
categories  String[]  jquerysamples 

The dependencies property informs CQ to include the CSS files and JQuery libraries in the page. The categories property informs CQ which clientlibs must be included.

After you create the Clientlibs folder, add the flexigrid CSS file, the flexigrid JS file, the JQuery library file, and two map text files.

Text files

You have to add two text files to the clientlibs folder. These text files map to the JS files and the CSS file. The names of the text files are: css.txt and js.txt. The css.txt file contains the CSS file named flexigrid.pack.css. Likewise, the js.txt file contains the JS file names jquery-1.6.3.min.js and  flexigrid.pack.js.

Add the files to the ClientLibs folder 

  1. Right-click /apps/users/components then select New, Node.
  2. Make sure that the node type is cq:ClientLibraryFolder and name the node clientlibs.
  3. Right click on clientlibs and select Properties. Add the two properties specified in the previous table to the node.
  4. On your file system, navigate to the folder where the JQuery JS files are located. Drag and drop the JS files to the clientlibs node by using CRXDE.
  5. On your file system, navigate where you placed the CSS files. Drag and drop the CSS files to the clientlibs folder by using CRXDE.
  6. Add a TXT file to the clientlibs folder named js.txt. Add the content specified in this section.
  7. Add a TXT file to the clientlibs node named css.txt. Add the content specified in this section.

Modify the render component to invoke UserManager operations 

To create an Experience Manager application that invokes Experience Manager User Manager operations, create these files:

adduser.json.jsp: contains application logic that adds a new user.
userTemplate.json.POST.jsp: contains application logic that calls the User Manager operation that retrieves all users.
userTemplate: add application logic that uses AJAX to either retrieve Experience Manager users or add a new user (this file was created earlier; however, you modify it in this step).

adduser.json.jsp 

Add a new JSP file named adduser.json.jsp to the following JCR path:

/apps/users/components/page/userTemplate

In adduser.json.jsp, create a UserManagerFactory instance by using the sling.getService method, as shown in the following example:

final UserManagerFactory umFactory = sling.getService(UserManagerFactory.class);

You pass the class name of the UserManagerFactory to the sling.getService method. This method returns a UserManagerFactory instance. You use the UserManagerFactory instance to create a UserManager instance that you can use to add a new user to Experience Manager. However, before you can create a UserManager object, you must create a Session instance. 

To create a Session instance, you use a SlingRepository instance, as shown in the following code example.

final SlingRepository repos = sling.getService(SlingRepository.class);

Session session = null;

try
{
    // Ensure that the currently logged on user has admin privileges
    //Create a Session instance
    session = repos.loginAdministrative(null);

    ....

Once you have a Session instance, you can create a UserManager instance that lets you add a new Experience Manager user.

final UserManager um = umFactory.createUserManager(session);

To add a new user, invoke the UserManager object's createUser method and pass the following arguments:

  • A String value that specifies the users' id value.
  • A String value that specifies the corresponding password.
  • A String value that specifies the principal name. 

The following JavaScript code represents the entire adduser.json.jsp file.

<%@page session="false" %>
<%@include file="/libs/foundation/global.jsp"%>
<%@ page import="org.apache.sling.jcr.api.SlingRepository" %>
<%@ page import="com.day.cq.security.UserManager" %>
<%@ page import="com.day.cq.security.UserManagerFactory" %>
<%@ page import="com.day.cq.security.User" %>
<%@ page import="com.day.cq.security.Authorizable" %>
<%@ page import="com.day.cq.security.profile.Profile" %>
<%@ page import="java.util.Iterator" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="org.apache.sling.commons.json.io.*" %>
<%@ page import="com.day.cq.commons.TidyJSONWriter" %><%


String userId = request.getParameter("first");
String password = request.getParameter("password");
String principalName = request.getParameter("principalName");

final SlingRepository repos = sling.getService(SlingRepository.class);
final UserManagerFactory umFactory = sling.getService(UserManagerFactory.class);

Session session = null;
Iterator<User> userIterator = null;
Iterator<Authorizable> authorizableIterator = null;
try
{
    // Ensure that the currently logged on user has admin privileges.
    session = repos.loginAdministrative(null);
    
    final UserManager um = umFactory.createUserManager(session);
    final TidyJSONWriter writer = new TidyJSONWriter(response.getWriter());
        
    //Add a new user to Adobe CQ
    um.createUser(userId, password, principalName) ;
    
    String Response = "User "+ userId + " was added to CQ";   
    
    //Send the data back to the client using a TidyJSONWriter object
    writer.setTidy("true".equals(request.getParameter("tidy")));
    writer.object();
    writer.key("key").value(Response);
    writer.endObject();

}
catch (Exception e)
{
    System.out.println("myajaxsample Exception Occured: " + e.getMessage());
}
finally
{
    session.logout(); 
    session = null;
}
%> 

userTemplate.json.POST.jsp 

The userTemplate.json.POST.jsp file contains JavaScript application logic that retrieves all Experience Manager users. This application logic also creates a UserManager instance as explained earlier in this section. To retrieve Experience Manager users, you invoke the UserManager object's getUsers method.  This method returns an Iterator<User> collection object that you can iterate through. 

In this sample application, user data is displayed in the flexigrid plugin. To successfully display the data in the flexigrid plugin, the data has to be formatted as JSON:

total: (no of rec)
 page : (page no)
 rows : [{cell: [ (col1 value) , (col2 value) ,.. ] },
        {cell: [ (col1 value) , (col2 value) ,.. ] }]

You can use a com.day.cq.commons.TidyJSONWriter instance to get the data into JSON format.  The following JavaScript code represents the userTemplate.json.POST.jsp  file.

<%@page session="false" %>
<%@include file="/libs/foundation/global.jsp"%>
<%@ page import="org.apache.sling.jcr.api.SlingRepository" %>
<%@ page import="com.day.cq.security.UserManager" %>
<%@ page import="com.day.cq.security.UserManagerFactory" %>
<%@ page import="com.day.cq.security.User" %>
<%@ page import="com.day.cq.security.Authorizable" %>
<%@ page import="com.day.cq.security.profile.Profile" %>
<%@ page import="java.util.Iterator" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="com.day.cq.commons.TidyJSONWriter" %>

<%

//Local variables
final SlingRepository repos = sling.getService(SlingRepository.class);
final UserManagerFactory umFactory = sling.getService(UserManagerFactory.class);

Session session = null;
Iterator<User> userIterator = null;
Iterator<Authorizable> authorizableIterator = null;
try
{
    // Ensure that the currently logged on user has admin privileges.
    session = repos.loginAdministrative(null);
    
    final UserManager um = umFactory.createUserManager(session);
    final TidyJSONWriter writer = new TidyJSONWriter(response.getWriter());
    
    userIterator = um.getUsers();
    List<User> users = new ArrayList<User>();
    User tmpUser;
    
    // copy iterator into a List for additional manipulations.
    while(userIterator.hasNext())
    {
        tmpUser = userIterator.next();
        users.add(tmpUser);
        
    }
    
    //Begin writing JSON response
    writer.setTidy("true".equals(request.getParameter("tidy")));
    writer.object();
    writer.key("page").value(1);
    writer.key("total").value(users.size());
    writer.key("rows").array();
    
    
    for(int i=0; i < users.size(); i++)
    {
        
        User aUser = users.get(i);
        Profile aProfile = aUser.getProfile();
        
        writer.object();
        writer.key("id").value(aUser.getID());
        writer.key("cell").array();
        writer.value(aUser.getID());
        writer.value(aProfile.getGivenName());
        writer.value(aProfile.getFamilyName());
        writer.value(aProfile.getPrimaryMail());
        writer.endArray();
        writer.endObject();
    }
        
        writer.endArray();
        writer.endObject();
        session.logout();
}
catch (Exception e)
{
    System.out.println("myajaxsample Exception Occured: " + e.getMessage());
}
finally
{
    session.logout(); 
    session = null;
}
%>

Modify the userTemplate.jsp file

Modify the userTemplate.jsp file to call both the adduser.json.jsp and the userTemplate.json.POST.jsp. In this example, a JQuery Ajax HTTP request is used and the corresponding values are passed. The following JavaScript code represents the userTemplate.jsp file.

<%@include file="/libs/foundation/global.jsp"%>
<cq:includeClientLib categories="jquerysamples" />
<script type="text/javascript">

/* Grab the JCR path to the content entry that calls this component
 * with Sling, you cannot call a script, you must call the jcr content
 * node that resolves to the representation (script).
 */ 
var baseURL = "<%= currentNode.getPath() %>";

jQuery(function ($) {

	$('#submit').click(function() {
	    var failure = function(err) {
	      //  $(".main").unmask();
	        alert("Unable to retrive data "+err);
	          
	    };
	      
	      
	    //Get the user-defined values to persist in the database
	    var myFirst= $('#first').val() ; 
	    var password= $('#password').val() ; 
	    var principalName= $('#principalName').val() ; 
	   
	      
	    var url = location.pathname.replace(".html", "/_jcr_content.adduser.json") + "?first="+ myFirst +"&password="+password +"&principalName="+principalName ;
	   	   	  
	    $.ajax(url, {
	        dataType: "text",
	        success: function(rawData, status, xhr) {
	            var serverResponse;
	            try {
	            	serverResponse = $.parseJSON(rawData);
	            	
	                alert(serverResponse.key); 
	  	                
	             
	            } catch(err) {
	                failure(err);
	            }
	        },
	        error: function(xhr, status, err) {
	            failure(err);
	        } 
	    });
	  });
	 



    $('.useraccount-table').flexigrid({
        url: baseURL + '.json', // this will trigger the JSON selector in Sling  
        dataType: 'json', // NOTE: Flexigrid executes a POST, not GET to retrieve data
        colModel : [ {
            display : 'User ID', name : 'id', width : 215, sortable : true, align : 'left', hide: false
        }, {
            display : 'First Name', name : 'givenName', width : 100, sortable : true, align : 'left', hide: false
        }, {
            display : 'Last Name', name : 'familyName', width : 100, sortable : true, align : 'left', hide: false
        },{
            display : 'Email', name : 'email', width : 215, sortable : true, align : 'left', hide: false
        }], 
        buttons : [
            {name: 'Add', bclass: 'add', onpress : test},
            {name: 'Edit', bclass: 'edit', onpress : test},
            {name: 'Delete', bclass: 'delete', onpress : test},
            {separator: true}
            ],
       searchitems : [
            {display: 'User ID', name : 'user_id',isdefault: true},
            {display: 'First Name', name : 'givenName'},
            {display: 'Last Name', name : 'familyName'}
            ],
        sortname: "id",
        sortorder: "asc",
        usepager: true,
        title: "Adobe CQ5 Users",
        useRp: true,
        rp: 15,
        showTableToggleBtn: false,
        singleSelect: true,
        width: 700,
        height: 200
    });
});

function test() {
    alert("Not implemented yet.");
}

</script>

<body>
<div class="wrapper">
    <div class="header">
        <p class="logo">Adobe User Manager app</p>
    </div>
    <div class="content">
    <div class="main">
    <h1>Adobe User Manager app</h1>
      
    <form name="signup" id="signup">
     <table>
    <tr>
    <td>
    <label for="first">First Name:</label>
    </td>
     <td>
    <input type="first" id="first" name="first" value="" />
    </td>
    </tr>
    <tr>
    <td>
    <label for="password">Password:</label>
    </td>
     <td>
    <input type="password" id="password" name="password" value="" />
    </td>
    </tr>
     <tr>
    <td>
    <label for="principalName">Principal Name:</label>
    </td>
     <td>
    <input type="principalName" id="principalName" name="principalName" value="" />
    </td>
    </tr>
         
</table>
            <div>
                <input type="button" value="Add A CQ User"  name="submit" id="submit" value="Submit">
            </div>
        </form>
        </div>
    </div>
      <div>
<table class="useraccount-table"></table><!-- Rendered by Flexigrid jQuery plugin -->
</div>
</body>
</html>




To modify the userTemplate JSP

  1. To view the CQ 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 Tool in the left menu).
  3. Double-click apps/users/components/page/userTemplate/userTemplate.jsp.
  4. Replace the JSP code with the new code shown in this section.
  5. Click Save All.

Create an AEM web page that displays users 

The final task is to create a site that contains a page that is based on the userTemplate (the template created earlier in this development article). When the fills in the form and clicks the Add User button, a new user is added to Experience Manager. You can refresh the page to see the user in the data grid.

UserGrid2


Create a AEM web page that queries and persists data from the AEM JCR:

  1. Go to the welcome page at http://[host name]:[port]; for example, http://localhost:4502.
  2. Select Websites. (If you are using AEM 5.6, click Tools from the menu on the left.)
  3. From the left hand pane, select Websites.
  4. Select New Page.
  5. Specify the title of the page in the Title field.
  6. Specify the name of the page in the Name field.
  7. Select userTemplate 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.
  8. Open the new page that you created by double-clicking it in the right pane. The new page opens in a web browser. CQ users are displayed in the data grid control as shown in the previous illustration.  

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