Article summary

Summary
Discusses how to create a dynamic Adobe Experience Manager web client that is able to invoke an Experience Manager OSGi bundle operation. This article uses a JSONWriter instance to pass data to the web client. In addition, discusses how to use a client library to style the web client.
Digital Marketing Solution(s) Adobe Experience Manager (Adobe CQ)
Audience
Developer (intermediate)
Required Skills
Java, JQuery, JSON, CSS
Tested On Adobe Experience Manager 5.5, 5.6

Note:

This article uses a JSP and is for Experience Manager 5.5 or 5.6. If you are using Experience Manager 6,x, then it is recommended that you use HTL. For information about creating a similiar dynamic web client, see Creating an AEM HTML Template Language Component that posts data using AJAX.

Introduction

You can use an org.apache.sling.commons.json.io.JSONWriter instance to dynamically display data that is returned by an Adobe Experience Manager OSGi bundle operation within a client web page. A JSONWriter instance lets you define value and key methods used to display data. For example, consider the OSGi bundle that consumes a third-party web service to return weather information. (For information, see Creating Experience Manager bundles that consume web services.)

Note:

To follow along with this development article, create the OSGi bundle that consumes the third-party web service by following the article referenced in the previous link.

You can use a JSONWriter instance to return weather data based on user input. For example, consider the following graphical user interface that lets a user select a US ZIP code from a drop-down menu.

JSON1

When the user selects a US zip code from the drop-down menu and clicks the Click Me button, the weather service OSGi bundle is invoked. A JSONWriter instance is used to display the data returned by the OSGi bundle in the client web page, as shown in the following illustration.

JSON2

In addition to discussing how to use a JSONWriter instance to return data from an OSGi bundle operation, this article also discusses how to use a cq:ClientLibraryFolder node and a CSS file to style the JSP front end. See Using Client-Side HTML Libraries.

Create an Experience Manager application folder structure

You can create an Experience Manager application that contains templates, components, and pages. Before you create application assets such as templates and pages, you create an application folder structure by using CRXDE Lite.

CQAppSetup

The following list 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 that you can base page components on. 
  • src: contains source code that comprises an OSGi component (this development does not create an OSGi bundle using this folder). 
  • install: contains a compiled OSGi bundles container.

The following illustration shows the folder structure that is created for this application. Notice that the application name is weatherappJSON.

CRXDE

To create an application folder structure, 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.
  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 weatherappJSON.
  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 an 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.

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 templateJSON.
  • 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 weatherappJSON/components/page/templateJSON.
  • 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 Experience Manager developer to create scripts that perform specific functionality. For more information about components, see Components.

Note:

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.

3. Right-click /apps/ weatherappJSON/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 templateJSON.
  • 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 weatertemplate.jps located at: /apps/weatherappJSON/components/page/templateJSON/templateJSON.jsp.

8. Enter the following JSP code:

<html>
<head>
<title>Hello World !!!</title>
</head>
<body>
<h1>Hello Web Services</h1>
<h2>This page will contain data from a third-party web service</h2>
</body>
</html>

Add CSS and JQuery files to a cq:ClientLibraryFolder node

You add a CSS file and a JQuery framework file to a cq:ClientLibraryFolder node to define the style of the client web page. The JQuery framework file used in this example is jquery-1.6.3.min.js.

Note:

For more information about using JQuery within Experience Manager, see http://scottsdigitalcommunity.blogspot.ca/2012/02/integrating-jquery-framework-into-day.html.

Add these properties to the clientlib node.

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

The dependencies property informs Experience Manager to make sure that the CSS and JQuery libraries are included in the page. The categories property informs Experience Manager which clientlibs must be included with the JSP that is generated.

Contents of the ClientLibs folder

Once you create the clientlibs folder, you add several files to it: a CSS file, the JQuery library file, and several map text files. The following illustration shows the clientlibs folder.

ClientLibsFolder22

The CSS file defines the display style for the client web page that lets the user submit a US Zip code to the OSGi operation. The following code represents the site.css file.

/* reset */
html, body, div, span, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
 margin: 0;
 padding: 0;
 border: 0;
 font-size: 100%;
 font: inherit;
 vertical-align: baseline;
}
html , body{
 line-height: 1;
 background-color: #334873;
 background-image: url(../_images/bg-page2.png);
}

ol, ul {
 list-style: none;
}


table {
 border-collapse: collapse;
 border-spacing: 0;
}
/* end reset*/



h1, h2, h3 {
 font-family: 'ColaborateRegular', Arial, sans-serif; 
}


strong {
 font-family: 'ColaborateMediumRegular', Arial, sans-serif; 
}

em {
 font-family: 'ColaborateThinRegular', Arial, sans-serif; 
}

.content {
 max-width: 760px;
 margin: 20px 0 0 100px;
}

.clear:after { 
content: "."; display: block; height: 0; clear: both; visibility: hidden; 
}

.clear {
 min-height: 1px;
}

* html .clear {
 height: 1px;
}

.header {
 position: relative;
 border-top: solid 6px white;
 padding: 10px 0 10px 0;
 margin-bottom: 20px;
}


.main {
 xxposition: relative;
 padding-bottom: 1em;
 border-bottom: solid 1px rgba(255,255,255,.5);
 xxoverflow:hidden;
 xxmin-height: 300px;
}

.main h1 {
 font-size: 32px;
 color: white;
 text-shadow: 1px 1px 1px rgba(0,0,0,.75);
 border-bottom: solid 1px rgba(255,255,255,.5);
 margin-bottom: 0.75em;
}


p , li, legend , form{
 font-size: 18px;
 color: white;
 font-family: 'ColaborateLightRegular', Arial, sans-serif;
 line-height: 125%;
 margin-bottom: 10px;
}

fieldset {
 padding: 10px;
 border: 1px solid white;
 margin: 25px 0; 
}

.nav {
 margin: 10px 0 0 100px; 
}

.nav li {
 display: inline-block; 
}

.nav a:hover, .example:hover{
 background-color: rgba(255,255,255,.85);
 color: rgb(0,0,0);
}

h3 {
 font-size: 18px;
 color: rgb(227,198,133);;
}

.results h2 {
 color: rgba(255,255,255,1);
}
.results div {
 padding-bottom: 10px;
}
.results div code {
 float: right;
 width: 60%;
}

input {
 font-size: 20px;
}
.form .wide {
 font-size: 18px;
 width: 100%;
}
.resultSection {
 float: right;
 width: 45%;
 margin-left: 20px;
}
#regexTester {
 margin-right: 55%;
}
.sideBySide li {
 float: left;
 overflow: hidden;
 width: 220px;
}
.clickable {
 cursor:pointer;
 margin-bottom: 5px;
}

.clickable:hover {
background-color:#FFC;
}


.col1 {
 float: left;
 width: 75%; 
}
.col2 {
 float: right;
 width: 20%; 
}

.col2 ul {
 margin-left: 20px;
 list-style: square;
}
.col2 li {
 font-size: 90%; 
}


#selectorList {
 overflow: hidden; 
}
#selector {
 width: 275px;
}


form#signup .label {
 width: 200px; 
} 

You have to add two text files to the clientlibs folder. These text files map to the jquery-1.6.3.min.js file and the site.css file. The names of the text files are: css.txt and js.txt. The content of the css.txt file is site.css. Likewise, the content of the js.text file is jquery-1.6.3.min.js. 

To add required files to the clientlibs folder, perform these tasks:

  1. Right-click /apps/weatherappJSON/components then select New, Node.
  2. Make sure 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 file is located. Drag and drop jquery-1.6.3.min.js to the clientlibs node by using CRXDE. 
  5. On your file system, navigate where you placed the CSS file. Drag and drop site.css to the clientlibs folder by using CRXDE.
  6. Add a TXT file to the clientlibs folder named js.txt (the content of this file is shown earlier).
  7. Add a TXT file to the clientlibs node named css.txt (the content of this file is shown earlier).

Modify the render component to use a JSONWriter instance

To use a JSONWriter object as a connection between the front-end JSP and the backend OSGi bundle, create these two files:

  • lookup.json.jsp: contains application logic that creates a JSONWriter object and calls the OSGI bundle operations. This file is the connection between a JSP front end and the back end OSGi operations. 
  • templateJSON.jsp: contains application logic that defines the JSP that lets a user select a US Zip code value and submit the value. The return value from the OSGi (weather information) is displayed in the JSP and displayed to the end user.

Note:

The templateJSON.jsp file was created in an earlier step; however, in this step, you use new JavaScript code.

Creating the lookup.json.jsp file

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

/apps/weatherappJSON/components/page/templateJSON

In the lookup.json.jsp, create a JSONWriter instance that invokes operations of the OSGi bundle that returns weather data. To create a JSONWriter instance, ensure that you specify the following page import statements:

page import="org.apache.sling.commons.json.io.*,com.cdyne.ws.weatherws.*"

The first package allows you to create a JSONWriter instance. The second package allows you to use data types that are defined in the OSGi bundle. Data types defined in the com.cdyne.ws.weatherws.* package allows you to invoke operations exposed by the OSGi bundle.

The following code represents the lookup.json.jsp file:

<%@ page import="org.apache.sling.commons.json.io.*,com.cdyne.ws.weatherws.*" %><%
String zip = request.getParameter("zip");
Weather ww = new com.cdyne.ws.weatherws.Weather();
WeatherSoap ws = ww.getWeatherSoap();
WeatherReturn wr = ws.getCityWeatherByZIP(zip);


JSONWriter writer = new JSONWriter(response.getWriter());
writer.object();
writer.key("zip");
writer.value(zip);

writer.key("city");
writer.value(wr.getCity());

writer.key("state");
writer.value(wr.getState());

writer.key("description");
writer.value(wr.getDescription());

writer.key("wind");
writer.value(wr.getWind());

writer.key("temperature");
writer.value(wr.getTemperature());

writer.key("humidity");
writer.value(wr.getRelativeHumidity());
writer.endObject();
%>

Notice the request.getParameter method and its parameter named ZIP. This parameter corresponds to the ZIP field value submitted from the JSP. The remaining code creates a WeatherReturn instance based on the ZIP value. The wr instance is used with the JSONWriter object.

Notice how JSON key/value methods are called. That is, for each OSGi bundle method called (for example, wr.getCity()), a corresponding writer.key method is called.

To add the lookup.json.jsp file, 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.
  3. Right-click /apps/weatherappJSON/components/page/templateJSON, then select Create, File.
  4. Enter lookup.json.jsp in the Name field and click OK. 
  5. Enter the JSP code shown in this section. 
  6. Click Save All.

Modifying the templateJSON.jsp file

Modify the templateJSON.jsp file to call the JSONWriter object. The part of the JSP file that uses the JSONWriter is the submit method, that is called when the submit button is clicked.

$('#submit').click(function() {
  var failure = function(err) {
       $(".main").unmask();
        alert("Unable to retrive data "+err);
        // TODO - clear the form
  };
    
    
//Get the ZIP Code value to pass to the CQ Web Service
var myZip = $('#mydropdown').val() ; 
    
var url = location.pathname.replace(".html", "/_jcr_content.lookup.json") + "?zip="+myZip;
    
$(".main").mask("Loading...");

$.ajax(url, {
        dataType: "text",
        success: function(rawData, status, xhr) {
            var data;
            try {
             data = $.parseJSON(rawData);
             
             //Set the fields in the forum
             $('#city').val(data.city); 
             $('#state').val(data.state);
             $('#description').val(data.description);
             $('#wind').val(data.wind);
             $('#temp').val(data.temperature);
             $('#hum').val(data.humidity);
             $(".main").unmask();
            } catch(err) {
                failure(err);
            }
        },
        error: function(xhr, status, err) {
            failure(err);
        } 
    });

To use the JSONWriter instance defined in the lookup.json.jsp file, define an url variable, as shown in the following line of code:

var url = location.pathname.replace(".html", "/_jcr_content.lookup.json") + "?zip="+myZip;

This url variable is used in the $.ajax() method. Within this method, notice the following line of code:

data = $.parseJSON(rawData);

After this line of code, weather information retrieved from the OSGi is written to the HTML form’s fields. For example:

$('#city').val(data.city);

The following code represents the entire templateJSON.jsp file.

<%@include file="/libs/foundation/global.jsp"%>
<cq:includeClientLib categories="jquerysamples" />
<html>
<head>
<meta charset="UTF-8">
<title>Adobe Experience Manager Dynamic Web Service Weather Page</title>
<style>
#signup .indent label.error {
  margin-left: 0;
}
#signup label.error {
  font-size: 0.8em;
  color: #F00;
  font-weight: bold;
  display: block;
  margin-left: 215px;
}
#signup  input.error, #signup select.error  {
  background: #FFA9B8;
  border: 1px solid red;
}
</style>
<script>
$(document).ready(function() {
     
    $('body').hide().fadeIn(5000);
     
$('#submit').click(function() {
    var failure = function(err) {
         alert("Unable to retrive data "+err);
         
    };
     
     
    //Get the ZIP COde value to pass to the CQ Web Service
    var myZip = $('#mydropdown').val() ; 
     
    var url = location.pathname.replace(".html", "/_jcr_content.lookup.json") + "?zip="+myZip;
     
    
    $.ajax(url, {
        dataType: "text",
        success: function(rawData, status, xhr) {
            var data;
            try {
                data = $.parseJSON(rawData);
                 
                //Set the fields in the forum
                $('#city').val(data.city); 
                $('#state').val(data.state);
                $('#description').val(data.description);
                $('#wind').val(data.wind);
                $('#temp').val(data.temperature);
                $('#hum').val(data.humidity);
                } catch(err) {
                failure(err);
            }
        },
        error: function(xhr, status, err) {
            failure(err);
        } 
    });
  });
 
}); // end ready
</script>
</head>
<body>
<div class="wrapper">
    <div class="header">
        <p class="logo">Weather Page </p>
    </div>
    <div class="content">
    <div class="main">
    <h1>AEMWeb Service Example</h1>
        <form name="signup" id="signup">
         <table> 
            
           <tr>
           <td> 
             <label for="zip" class="label">Enter US Zip Code:</label>
            </td> 
            <td>    
                <select name="mydropdown" id="mydropdown" style="width: 200px;" >
                    <option value="90210">90210</option>
                    <option value="95101">95101</option>
                    <option value="94101">94101</option>
                </select>
            </td>
            </tr>
            <tr>
            <td> 
                <label for="city" class="label">City</label>
            </td>
            <td>      
                <input name="city" type="text" id="city" readonly="readonly">
            </td> 
            </tr>
            <tr>
            <td>
               <label for="state" class="label">State</label>
            </td> 
            <td>  
                <input name="state" type="text" id="state" readonly="readonly">
            </td>
            </tr>
            <tr>
            <td>             
                <label for="description" class="label">Description</label>
            </td>
            <td>     
                <input name="description" type="text" id="description" readonly="readonly">
            </td> 
            </tr>
            <tr>
            <td>
                <label for="wind" class="label">Wind</label>
            </td>
             <td>     
                <input name="wind" type="text" id="wind" readonly="readonly">
             </td>
             </tr>                
            <tr>
            <td>
                <label for="temp" class="label">temperature</label>
            </td>   
            <td> 
                <input name="temp" type="text" id="temp" readonly="readonly">
            </td>
             </tr>
            <tr>
            <td>
             
            <div><label for="hum" class="label">Humidity</label>
            </td>
            <td>
              <input name="hum" type="text" id="hum" readonly="readonly">
          </td>
         </tr>  
         <tr>
         <td>
         </td>
            <td>
                <input type="button" value="Get Weather!"  name="submit" id="submit" value="Submit">
            </td>
            </tr> 
        </form>
        </table>
        </div>
    </div>
     
</div>
</body>
</html>

Notice this line at the top of the JSP:

<cq:includeClientLib categories="jquerysamples" />

The categories attribute maps to the property that was added to the clientlibs node. This is how Experience Manager locates the JQuery framework and the CSS files. 

To modify the lookup.json.jsp file, 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.
  3. Double-click apps/weatherappJSON/components/page/templateJSON/templateJSON.jsp.
  4. Replace the JSP code with the new code shown in this section. 
  5. Click Save All.

Create a page that displays data retrieved from the OSGi bundle

Create a site that contains a page that is based on templateJSON (the template created earlier in this development article).

To create a web page that displays data retrieved from an OSGi bundle, 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 Websites.
  3. From the left hand pane, select Websites. 
  4. Select New, 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 templateJSON 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 when creating the template, 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. You should see a page displaying data similar to the illustration at the beginning of this article.

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