Creating multi page application in WorkLight

WorkLight allows you to create multi-page application, i wanted to try this feature, so i changed the Contact Search application that i created in Using BusyIndicator common control entry, so that, when executes a search for contact, it returns list of contact names, user can click on one of the contact name to go to the Contact Details page and that page has button that allows user to go back to Summary page. This is how my summary page looks like
When you click on the arrow button next to any user name it takes you to the Details page for that contact which looks like this
You can click on the Summary button on the Details page to go back to the Contact Summary page. I followed these steps to create this sample application
  1. First i changed the main or landing page of my app to mark the div where the new page should be inserted, i did that by setting value of id element to pagePort like this
    
    !DOCTYPE html>
    <html>
    <head>
    ....
    </head>
    <body onload="WL.Client.init({showLogger:true})" id="content"
      style="display: none">
    
      <div data-role="page" id="page1">
        <div data-theme="a" data-role="header">
          <h3>Contact DB App</h3>
        </div>
        <div data-role="content" id="pagePort" >
          <div data-role="fieldcontain">
            <fieldset data-role="controlgroup">
              <label for="textinput1"> First Name </label> <input
                id="contactName" placeholder="" value="" type="text" />
            </fieldset>
          </div>
          <a data-role="button" data-transition="fade"
            href="javascript:getContact()" id="searchContact"> Search
            Contact </a>
          <ul data-role="listview" data-inset="true" data-filter="true"
            id="displayContact">
          </ul>
        </div>
        <div data-theme="a" data-role="footer">
          <h3>Copyright stuff</h3>
        </div>
      </div>
      <script src="js/HelloDatabase.js"></script>
      <script src="js/messages.js"></script>
      <script src="js/auth.js"></script>
    </body>
    </html>
    
  2. Then i did create this new contactDetail.html page in the same directory as that of my first/landing page
    
    <div data-role="content" id="mainContent">
      <div data-role="fieldcontain">
        <fieldset data-role="controlgroup">
          <label for="firstName"> First Name </label> 
          <input id="firstName" placeholder="" value="" type="text" readonly="readonly" />
          <label for="lastName"> Last Name </label> 
          <input id="lastName" placeholder="" value="" type="text" readonly="readonly"/>
          <label for="email"> Email </label> 
          <input id="email" placeholder="" value="" type="text" readonly="readonly"/>
          
          <a data-role="button" data-transition="fade"
            href="javascript:showSummary()" id="searchContact"> Summary </a>
        </fieldset>
      </div>
    </div>
    
    The Details page shows the form with contact details and it has a Summary button that allows user to go back to the summary page, when you click on that button it will pass control to showSummary() method
  3. I had to make changes to my main JavaScript function to make it look like this
    
    var busyIndicator;
    function wlCommonInit() {
      busyIndicator = new WL.BusyIndicator('page1');
    }
    
    function getContact() {
      console.log("Entering getContact() REST service based version");
      var contactName = $('contactName').getValue();
      var invocationData = {
        adapter : "ContactWSService",
        procedure : "searchContact",
        parameters : [ contactName ]
      }
      var options = {
        onSuccess : loadContactSuccess,
        onFailure : loadContactFailure
      }
      busyIndicator.show();
      WL.Client.invokeProcedure(invocationData, options);
    }
    
    function loadContactSuccess(result) {
      console.log("Inside loadContactSuccess " + result);
      var html = '';
      try {
        if (result.status == 200) {
          var contactList = result.invocationResult.Envelope.Body.searchContactResponse.contactList;
          var i = 0;
          for (i = 0; i < contactList.length; i++) {
            var currentContact = contactList[i];
            html = html + '<li><a href="javascript:showContactDetail('
                + currentContact.contactId + ')">'
                + currentContact.firstName + ' '
                + currentContact.lastName + '</a></li>';
          }
        }
        jq("#displayContact").html(html);
        jq("#displayContact").listview('refresh');
        busyIndicator.hide();
      } catch (e) {
        busyIndicator.hide();
      }
    }
    function showContactDetail(contactId) {
      console.log("Show Contact Detail is clicked " + contactId);
      WL.Page.load("contactDetail.html", {
        onComplete : function() {
          console.log("After fragment is loadded ");
          jq('#mainContent').trigger("create");
          getContactDetails(contactId);
        },
        onUnload : function() {
          console.log("After fragment is unloadded ");
        }
      });
    }
    
    function showSummary() {
      WL.Page.load("contactSummary.html", {
        onComplete : function() {
          console.log("After fragment is loadded ");
          jq('#mainContent').trigger("create");
          
        },
        onUnload : function() {
          console.log("After fragment is unloadded ");
        }
      }); 
    }
    
    function getContactDetails(contactId) {
      console.log("Entering getContactDetails()");
      var invocationData = {
        adapter : "ContactWSService",
        procedure : "getContact",
        parameters : [ contactId ]
      }
      var options = {
        onSuccess : getContactDetailsSuccess,
        onFailure : getContactDetailsFailure
      }
      busyIndicator.show();
      WL.Client.invokeProcedure(invocationData, options);
    }
    
    function getContactDetailsSuccess(result) {
      console.log("Entering getContactDetailsSuccess");
      try {
        if (result.status == 200) {
          var displayContact = result.invocationResult.Envelope.Body.getContactResponse.contact;
          $('firstName').value=displayContact.firstName;
          $('lastName').value=displayContact.lastName;
          $('email').value=displayContact.email;
        }
        busyIndicator.hide();
      } catch (e) {
        busyIndicator.hide();
      }
    }
    function getContactDetailsFailure(result) {
      console.log("Entering getContactDetailsFailure");
    }
    
    I had to make quite a few changes in my JavaScript they are as follows
    • loadContactSuccess: The loadContactSuccess method gets called when you execute search and it gets back the result, this method generates one row each for the result. I changed this method so that when it was generating the list i did attach getContactDetails(contactId) method to each row
    • showContactDetail: The showContactDetail method will get called when user clicks on any of the user name, when that happens i am calling WL.Page.load("contactDetails.html" method which replaces the markup inside the page with contactDetail.html, this method also calls the getContactDetails which calls SOAP service with contactId to get details of the contact.
    • showSummary: The showSummary method will be called when user clicks on the Summary button on the details page, it again calls WL.Page.load("contactSummary.html" to replace the markup in the current page with the contact details

Forcing jQuery Mobile to re-evaluate styles/theme on dynamically inserted content

Today i was trying to build a JQuery Mobile application that has multiple pages. When user clicks on the page switch button i take the markup on the new page and insert it in the old page. One problem that i noticed is when you insert HTML into a page and that HTML has jQuery UI widgets then those widgets do not get evaluated, instead jQuery Displays them without any styles. You can solve this problem by calling the $('changedDiv').trigger("create") method with value of the div equal to id where the new markup got inserted


<div id='changedDiv'>
//Insert jQuery widgets here
</div>

Using WL.SimpleDialog() to display error

I wanted to figure out how to use WL.SimpleDialog() so i used it to change the contact application that i developed in Using BusyIndicator common control so that if there is JavaScript Exception during searching of contact it displays that error in Dialog Box like this
This is how my JavaScript looks like after the changes

var busyIndicator;
function wlCommonInit(){
  busyIndicator = new WL.BusyIndicator('page1');
}
function getContact(){
  console.log("Entering getContact() REST service based version");
  var contactName = $('contactName').getValue();
  var invocationData = {
      adapter:"ContactWSService",
      procedure:"searchContact",
      parameters:[contactName]
  }
  var options ={
      onSuccess:loadContactSuccess,
      onFailure:loadContactFailure
  }
  busyIndicator.show();
  WL.Client.invokeProcedure(invocationData, options);
}

function loadContactSuccess(result){
  console.log("Inside loadContactSuccess " + result);
  var html = '';
  try{
  if(result.status == 200){
    var contactList = result.invocationResult.Envelope.Body.
 searchContactResponse.contactList;
    var i = 0;
    for(i =0 ; i < contactList.length ; i++){
      var currentContact = contactList[i];
      html =  html + '<li><a href="#">'+currentContact.firstName 
   +' ' +currentContact.lastName +'</a></li>';
    }   
  }
  jq("#displayContact").html(html);
  jq("#displayContact").listview('refresh');
  busyIndicator.hide();
  }catch(e){
    busyIndicator.hide();
    displayError(e.toString());
  }
}

function loadContactFailure(result){
  console.log("Inside loadContactError " + result);
  busyIndicator.hide();
  displayError(result);
}

function displayError(errorString) {
  var dialogTitle = "Error";
  WL.SimpleDialog.show(dialogTitle, errorString, [ {
    text : 'OK',
    handler : simpleDialogButton1Click
  }
  ]);
}
function simpleDialogButton1Click() {
}

First i did create a displayError() method that takes error message as input and displays it in Modal dialog that has only one button. The simpleDialogButton1Click() would get called when user clicks on OK in the Error dialog but it does not do anything. The displayError() method is getting called from the exception handler class as well as the loadContactFailure() class.

Using BusyIndicator common control

I wanted to try using the BusyIndicator so i decided to change the Contact Search application that i developed in Using JQuery Mobile in WorkLight application entry, so that as soon as user clicks on Search Contact it starts showing the busy indicator and that indicator stays still the results are updated. I made following changes in my JavaScript file.


var busyIndicator;
function wlCommonInit(){
  busyIndicator = new WL.BusyIndicator('page1');
}
function getContact(){
  var contactName = $('contactName').getValue();
  var invocationData = {
      adapter:"ContactWSService",
      procedure:"searchContact",
      parameters:[contactName]
  }
  var options ={
      onSuccess:loadContactSuccess,
      onFailure:loadContactFailure
  }
  busyIndicator.show();
  
  WL.Client.invokeProcedure(invocationData, options);
}

function loadContactSuccess(result){
  console.log("Inside loadContactSuccess " + result);
  var html = '';
  try{
  if(result.status == 200){
    var contactList = result.invocationResult.Envelope.Body.searchContactResponse.contactList;
    var i = 0;
    for(i =0 ; i < contactList.length ; i++){
      var currentContact = contactList[i];
      html =  html + '<li><a href="#">'+currentContact.firstName +' ' 
   +currentContact.lastName +'</a></li>';
    }   
  }
  jq("#displayContact").html(html);
  jq("#displayContact").listview('refresh');
  
  busyIndicator.hide();
  
  }catch(e){
    busyIndicator.hide();
  }
}

function loadContactFailure(result){
  console.log("Inside loadContactError " + result);
  busyIndicator.hide();
}
First i had to create object of WL.BusyIndicator with value of page1 as input, page1 is the value of id attribute on enclosing div in my page. Without that i was getting JavaScript initialization error. Then the getContact() which is responsible for initiating the contact search call invokes the show() method to start the BusyIndicator. I am calling the hide() method of BusyIndicator in the loadContactSuccess() method which is a callback method that gets called once the results are ready and the UI is updated.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport"
  content="width=device-width, initial-scale=1.0, maximum-scale=1.0, 
  minimum-scale=1.0, user-scalable=0" />
<title>HelloDatabase</title>
<link rel="shortcut icon" href="images/favicon.png" />
<link rel="apple-touch-icon" href="images/apple-touch-icon.png" />
<link rel="stylesheet" href="css/reset.css" />
<link rel="stylesheet" href="css/HelloDatabase.css" />
<link rel="stylesheet" href="css/jquery.mobile-1.0.min.css" />
<script src="js/jquery-1.7.1.min.js"></script>
<script>
  var jq = jQuery.noConflict();
</script>

<script src="js/jquery.mobile-1.0.min.js"></script>
</head>
<body onload="WL.Client.init({showLogger:true})" id="content" style="display: none">
  <div data-role="page" id="page1">
    <div data-theme="a" data-role="header">
      <h3>Contact DB App</h3>
    </div>
    <div data-role="content">
      <div data-role="fieldcontain">
                    <fieldset data-role="controlgroup">
                        <label for="textinput1">
                           First Name
                        </label>
                        <input id="contactName" placeholder="" value="" type="text" />
                    </fieldset>
                </div>
                <a data-role="button" data-transition="fade" 
    href="javascript:getContact()" id="searchContact">
                    Search Contact
                </a>
      <ul data-role="listview" data-inset="true" data-filter="true" id="displayContact">
      </ul>
    </div>
    <div data-theme="a" data-role="footer">
      <h3>Copyright stuff</h3>
    </div>
  </div>
  <script src="js/HelloDatabase.js"></script>
  <script src="js/messages.js"></script>
  <script src="js/auth.js"></script>
</body>
</html>

WorkLight SOAP Service debugging

I ran into few issues while working on Accessing SOAP service from the WorkLight app blog entry and these are the solutions to those problems First problem was i had to build the SOAP request in JavaScript manually for use in the HTTP Adapter class and since this code runs on server i was not able to debug it, and i was not sure what message is getting built. So i used the WL.Logger.debug("SOAP Request " + searchContactRequest) call in my Adapter code and then when i hit the adapter it did write this log statement in \Worklight\server\log\server\server.log directory like this 2012-03-29 15:40:30,469 DEBUG [developer] (pool-7-thread-2:0ad7210e-9ed8-4c58-9b38-853d1918131b) SOAP Request <soapenv:Envelope xmlns:q0="http://webspherenotes.com" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Header> </soapenv:Header> <soapenv:Body> <q0:searchContact> <arg0>at</arg0> </q0:searchContact> </soapenv:Body> </soapenv:Envelope> The worklight server does take care of writing the response of the SOAP request into the same log file, so having log enabled for com.srndpt.adapters helps Also note that the WorkLight server takes care of converting the SOAP XML response into JSON This is the response of my SOAP Service <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> - <S:Body> - <ns2:searchContactResponse xmlns:ns2="http://webspherenotes.com"> - <contactList> <contactId>1</contactId> <email>sdpatil@gmail.com</email> <firstName>Sunil</firstName> <lastName>Patil</lastName> </contactList> - <contactList> <contactId>2</contactId> <email>patil.jiyas@gmail.com</email> <firstName>Jiya</firstName> <lastName>Patil</lastName> </contactList> - <contactList> <contactId>3</contactId> <email>patil.navyas@gmail.com</email> <firstName>Navya</firstName> <lastName>Patil</lastName> </contactList> </ns2:searchContactResponse> </S:Body> </S:Envelope> The WorkLight server takes that response and converts it into JSON object and sticks it into Result element like this {"responseID":"10","statusCode":200,"errors":[],"isSuccessful":true,"statusReason":"OK","Envelope":{"Body":{"searchContactResponse":{"ns2":"http://webspherenotes.com","contactList":[{"lastName":"Patil","contactId":"1","email":"sdpatil@gmail.com","firstName":"Sunil"},{"lastName":"Patil","contactId":"2","email":"patil.jiyas@gmail.com","firstName":"Jiya"},{"lastName":"Patil","contactId":"3","email":"patil.navyas@gmail.com","firstName":"Navya"}]}},"S":"http://schemas.xmlsoap.org/soap/envelope/"},"warnings":[],"info":[]}

Accessing SOAP service from the WorkLight app

In the Using JQuery Mobile in WorkLight application entry i built a WorkLight application that takes contact last name as input and uses it to search for contact by using WorkLight SQL adapter, i wanted to check if i can achieve same functionality by using SOAP service so these are the steps that i used
  1. First i did build a simple JAXWS service that takes last name of the contact as input parameter and returns list of contacts with matching last name, you can download the service that i used from here
  2. Next i used the WorkLight studio to create a HTTP Adapter, i used ContactWSService as name for that adapter
  3. After creating the adapter i change the ContactWSService-impl.js that was generated to look like this
    
    function searchContact(lastName) {
     var searchContactRequest = '<soapenv:Envelope '+  
       'xmlns:q0="http://webspherenotes.com" '+  
       'xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" '+  
       'xmlns:xsd="http://www.w3.org/2001/XMLSchema" '+  
       'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> '+  
       '<soapenv:Header> '+  
       '</soapenv:Header> '+  
      '<soapenv:Body> '+ 
      '<q0:searchContact> '+
       '<arg0>'+lastName+'</arg0> '+
       '</q0:searchContact> '+
       '</soapenv:Body> '+  
     '</soapenv:Envelope> ';
     WL.Logger.debug("SOAP Request " + searchContactRequest);
     var input = {
         method : 'post',
         returnedContentType : 'xml',
         path : '/ManageContactWS/contactws',
         body:{
          content: searchContactRequest.toString(),
          contentType: 'text/xml; charset=utf-8'
         }
     };
     return WL.Server.invokeHttp(input);
    }
    
    In order to make a SOAP request call you will have to create the SOAP message first, i used the Eclipse Web Services Explorer tool to first test my SOAP service and then copied the XML SOAP message that it used for request into my JavaScript file. Once i have the SOAP message in String format i used it to make HTTP POST call
  4. Next i had to change the ContactWSService.xml the deployment descriptor for my adapter to declare searchContact procedure, after changes the file looks like this
    
    <?xml version="1.0" encoding="UTF-8"?>
    <wl:adapter name="ContactWSService"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns:wl="http://www.worklight.com/integration"
      xmlns:http="http://www.worklight.com/integration/http">
    
      <displayName>ContactWSService</displayName>
      <description>ContactWSService</description>
      <connectivity>
        <connectionPolicy xsi:type="http:HTTPConnectionPolicyType">
          <protocol>http</protocol>
          <domain>localhost</domain>
          <port>9000</port>      
        </connectionPolicy>
        <loadConstraints maxConcurrentConnectionsPerNode="2" />
      </connectivity>
      <procedure name="searchContact"/>
    </wl:adapter>
    
  5. The last change was in the WorkLight application code where i make the adapter call and parse the returned results so that i can display them, This is how my .js file looks like
    
    function getContact(){
     console.log("Entering getContact() REST service based version");
     var contactName = $('contactName').getValue();
     var invocationData = {
       adapter:"ContactWSService",
       procedure:"searchContact",
       parameters:[contactName]
     }
     var options ={
       onSuccess:loadContactSuccess,
       onFailure:loadContactFailure
     }
     WL.Client.invokeProcedure(invocationData, options);
    }
    
    function loadContactSuccess(result){
     console.log("Inside loadContactSuccess " + result);
     var html = '';
     if(result.status == 200){
      var contactList = result.invocationResult.Envelope.Body.searchContactResponse.contactList;
      var i = 0;
      for(i =0 ; i < contactList.length ; i++){
       var currentContact = contactList[i];
       html =  html + '
  6. '+currentContact.firstName +' ' +currentContact.lastName +'
  7. '; } } jq("#displayContact").html(html); jq("#displayContact").listview('refresh'); } function loadContactFailure(result){ console.log("Inside loadContactError " + result); }
    Important Note: By default the JAXWS wraps the return value in XML element named return and the WorkLight server simply uses the same name while converting the XML result into JSON object, but that makes accessing the return element difficult in the client javascript because return is the JavaScript keyword and you can not use it in your code. So to get around this problem i had to change my sample web service and use JAXWS annotation to customize name of the return element to contactList

Developing JAXWS Service for deployment in GlassFish/JEE 5 compliant container

In the newer version of JEE you can use annotations for creating Web Service, i wanted to try this feature so i did create this simple JAX WS service that takes name/part of the name of contact as input and return list of contacts with same last name. You can download the JAXWS service from here First i did create a ContactWS.java class that looks like this

import java.util.List;

import javax.jws.*;
@WebService(name="ContactWS", serviceName="ContactWS", 
targetNamespace="http://webspherenotes.com")
public class ContactWS {
  
  @WebMethod(operationName="searchContact")
  @WebResult(name="contactList",partName="contactList")
  public List searchContact(String lastName) {
    ContactDAO contactDAO = new ContactDAOImpl();
    return contactDAO.searchContact(lastName);
  }

}
The ContactWS class implements web service. The next step is to declare this class as servlet in web.xml like this


<web-app xmlns="http://java.sun.com/xml/ns/javaee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
  http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  version="2.5">

  <display-name>Contact Web Service</display-name>

  <servlet>
    <servlet-name>ContactWS</servlet-name>
    <servlet-class>com.webspherenotes.ws.ContactWS</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>ContactWS</servlet-name>
    <url-pattern>/contactws/*</url-pattern>
  </servlet-mapping>

<
Once the application is deployed in the GlassFish server you can access it by going to http://localhost:9000/ManageContactWS/contactws

WorkLight HTTP Adapter returning XML

In the Invoking REST service from WorkLight entry i blogged about how to make a REST call that returns XML from WorkLight application using HTTP adapter. One thing that i noticed during that is even though my REST service returns XML WorkLight converts it into JSON for me and the generated JSON follows the same structure as that of the XML. This is how my XML response of the REST service looks like
The WorkLight server converts it into JSON and return's JSON that looks like this

Invoking REST service from WorkLight

In the Using JQuery Mobile in WorkLight application entry i blogged about how to create a simple Contact Search application that takes user's last name as parameter and searches all the contacts with that name displays to the user. In that example i used the WorkLight SQL adapter for making query, but i already have my own REST service that can do same thing and i wanted to use it.
This service takes part of last name as query parameter and returns all the contacts that match the name in XML format. I wanted to use this service in my WorkLight application, so that i could use the Http Adapter so i followed these steps
  1. First i did create a ContactRESTService adapter
  2. Then i changed the ContactRESTService-impl.js like this
    
    
    function getContactList() {
      var input = {
          method : 'get',
          returnedContentType : 'xml',
          path : '/ManageContact/rest/contact'
      };
      return WL.Server.invokeHttp(input);
    }
    
    function searchContact(lastName){
      var input = {
            method : 'get',
            returnedContentType : 'xml',
            path : '/ManageContact/rest/contact/search?lastName='+lastName
        };
        return WL.Server.invokeHttp(input);
    }
    
    
    function getStoriesFiltered(){
    }
    
    My adapter has 2 methods first is getContactList() that returns all the contacts in the database by calling /ManageContact/rest/contact URL and it does not take any parameter. The searchContact() takes lastName as parameter and makes GET call to '/ManageContact/rest/contact/search?lastName='+lastName URL.
  3. I also had to change the ContactRESTService.xml so that my adapter descriptor looks like this
    
    <?xml version="1.0" encoding="UTF-8"?>
    <wl:adapter name="ContactRESTService"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns:wl="http://www.worklight.com/integration"
      xmlns:http="http://www.worklight.com/integration/http">
    
      <displayName>ContactRESTService</displayName>
      <description>ContactRESTService</description>
      <connectivity>
        <connectionPolicy xsi:type="http:HTTPConnectionPolicyType">
          <protocol>http</protocol>
          <domain>localhost</domain>
          <port>9000</port>      
        </connectionPolicy>
        <loadConstraints maxConcurrentConnectionsPerNode="2" />
      </connectivity>
      <procedure name="getContactList"/>
      <procedure name="searchContact"/>
      <procedure name="getStoriesFiltered"/>
    </wl:adapter>
    
  4. After that i had to make couple of my minor change in my WorkLight application so that it would use the HTTP adapter instead of the SQL adapter, This is how my JavaScript that makes call to the adapter looks like
    
    function getContact(){
     console.log("Entering getContact() REST service based version");
     var contactName = $('contactName').getValue();
     var invocationData = {
       adapter:"ContactRESTService",
       procedure:"searchContact", 
       parameters:[contactName]
     }
     var options ={
       onSuccess:loadContactSuccess,
       onFailure:loadContactFailure
     }
     WL.Client.invokeProcedure(invocationData, options);
    }
    
    function loadContactSuccess(result){
     console.log("Inside loadContactSuccess " + result);
     var html = '';
     
     if(result.invocationResult.isSuccessful){
      var contactList = result.invocationResult.contacts.contact;
      var i = 0;
      for(i =0 ; i < contactList.length ; i++){
       var currentContact = contactList[i];
       html =  html + '<li><a href="#">'+currentContact.firstName +' ' 
    +currentContact.lastName +'</a></li>';
      }   
     }
     
     jq("#displayContact").html(html);
     jq("#displayContact").listview('refresh');
    }
    
    function loadContactFailure(result){
     console.log("Inside loadContactError " + result);
    }
    
    First the getContact() which makes call to the HttpAdapter had to changed to use the name of the ContactRESTService as adapter and searchContact as procedure name. Then i had to change the loadContactSuccess() method the part which reads the search results. Worklight makes sure that i get results in JSON format with little bit different structure.

WorkLight resources directory

You might have noticed that when you make changes in any HTML or JavaScript file in the WorkLight Studio those changes do not get reflected right away instead you will have to Right Click on the Project and say Run -< Build All and Deploy. It seems that when you click on Build and Deploy the Studio generates the files required for WorkLight and for every Environment in the Worklight\server\widget-resources directory like this
My HelloWorkLight project supports ipad and iphone environment so every time i click on the Build All and Deploy, WorkLight studio creates relevant directories under Worklight\server\widget-resources directory one is HelloWorlight-common-*, HelloWorkLight-ipad-*,HelloWorkLight-iphone-* the * represents a integer that worklight keeps incrementing. WorkLight studio copies all the application related files in these folders, if you make a change directly in of these files those changes get reflected right away but then you will not have those changes in your project and you those changes wont get picked after next deployment. If you open the files in these directories you will notice that WorkLight adds quite a few elements to it. For example this is my html file

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0, 
  maximum-scale=1.0, minimum-scale=1.0, user-scalable=0" />
        <title>HelloWorklight</title>
        <link rel="shortcut icon" href="images/favicon.png" />
        <link rel="apple-touch-icon" href="images/apple-touch-icon.png" />
        <link rel="stylesheet" href="css/reset.css" />
        <link rel="stylesheet" href="css/HelloWorklight.css" />        
    </head>
    <body onload="WL.Client.init({})" id="content" style='display: none'>
    <div id="AppBody">
      <div id="header">
        <div id="ReloadButton" onclick="reload();"></div>
        <h1>Basic Development</h1>
      </div>
      <div id="wrapper">
        <label for="actions">Display: </label>
        <select id="actions" onchange="displayInfo();">
          <option value="appEnvironment" selected="selected">Application Environment</option>
          <option value="language">Language</option>
        </select>
        <div id="info"></div>
      </div>
      <div id="worklight" onclick="loadWebPage();"></div>
    </div>

        <script src="js/HelloWorklight.js"></script>
        <script src="js/messages.js"></script>
        <script src="js/auth.js"></script>
    </body>
</html>
After deploy the same file gets changed to

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0, 
  maximum-scale=1.0, minimum-scale=1.0, user-scalable=0" />
        <title>HelloWorklight</title>
        <link rel="shortcut icon" href="images/favicon.png" />
        <link rel="apple-touch-icon" href="images/apple-touch-icon.png" />
        <link rel="stylesheet" href="css/reset.css" />
        <link rel="stylesheet" href="css/HelloWorklight.css" />        
    <link rel="stylesheet" href="wlclient/css/wlclient.css" />
    <link rel="stylesheet" href="xilinus/css/default.css" />
    <link rel="stylesheet" href="xilinus/css/alphacube.css" />
    <link rel="stylesheet" href="xilinus/css/debug.css" />
    <script type="text/javascript">
        // Define WL namespace. 
        var WL = WL ? WL : {};
        
        /** 
         * WLClient configuration variables.
         * Values are injected by the deployer that packs the gadget.
         */
        WL.StaticAppProps = {
          "APP_DISPLAY_NAME": "HelloWorklight",
          "APP_LOGIN_TYPE": "never",
          "APP_SERVICES_URL": "/apps/services/",
          "APP_VERSION": "1.0",
          "ENVIRONMENT": "preview",
          "HEIGHT": 460,
          "IID": 0,
          "LOGIN_DISPLAY_TYPE": "popup",
          "LOGIN_POPUP_HEIGHT": 610,
          "LOGIN_POPUP_WIDTH": 920,
          "LOGIN_REALM": null,
          "PREVIEW_ENVIRONMENT": "common",
          "TIMESTAMP": "192.168.94.131 on 2012-03-28 at 17:00:00",
          "WIDTH": 320,
          "WORKLIGHT_ROOT_URL": "/apps/services/api/HelloWorklight/common/0/"
    };
    </script>
    <script src="common/js/prototype.js"></script>
    <script src="common/js/containerCommunicationAPI.js"></script>
    <script src="common/js/base.js"></script>
    <script src="wlclient/js/messages.js"></script>
    <script src="common/js/wlcommon.js"></script>
    <script src="common/js/busy.js"></script>
    <script src="xilinus/js/window.js"></script>
    <script src="xilinus/js/debug.js"></script>
    <script src="wlclient/js/worklight.js"></script>
    <script src="wlclient/js/gadgetCommunicationAPI.js"></script>
    <script src="wlclient/js/wlclient.js"></script>
    <script src="wlclient/js/wlfragments.js"></script>
    <script src="wlclient/js/encryptedcache.js"></script>
    <script src="wlclient/js/blockTEA.js"></script>

  </head>
    <body onload="WL.Client.init({})" id="content" style='display: none'>
    <div id="AppBody">
      <div id="header">
        <div id="ReloadButton" onclick="reload();"></div>
        <h1>Basic Development</h1>
      </div>
      <div id="wrapper">
        <label for="actions">Display: </label>
        <select id="actions" onchange="displayInfo();">
          <option value="appEnvironment" selected="selected">Application Environment</option>
          <option value="language">Language</option>
        </select>
        <div id="info"></div>
      </div>
      <div id="worklight" onclick="loadWebPage();"></div>
    </div>

        <script src="js/HelloWorklight.js"></script>
        <script src="js/messages.js"></script>
        <script src="js/auth.js"></script>
    </body>
</html>

Enable tracing for WorkLight

When i was developing application accessing database from Worklight i wanted to debug to figure out what Query the SQL Adapter is making also i wanted to figure out how to enable the logging tracing for WorkLight product itself. There is a log4j.xml file in the Worklight\server\lib folder that you can change and restart the WorkLight server and then you can check the Worklight\server\log\server\server.log file for actual log statements For Example i did change the log level for com.srndpt.adapters package to DEBUG and then when i tried executing the code that uses adapter to make SQL query can i could see following log statements 2012-03-28 15:50:27,326 DEBUG [SQLQuery] (pool-1-thread-2:682f4681-e757-4a24-b20a-34f655f48c68) Prepare statement: select * FROM CONTACT WHERE FIRSTNAME LIKE ? 2012-03-28 15:50:27,326 DEBUG [SQLQuery] (pool-1-thread-2:682f4681-e757-4a24-b20a-34f655f48c68) Execute the query 2012-03-28 15:50:27,326 DEBUG [SQLQuery] (pool-1-thread-2:682f4681-e757-4a24-b20a-34f655f48c68) payload received.

Using JQuery Mobile in WorkLight application

In the Connecting to Database from WorkLight i blogged about how to build WorkLight application that talks to database, that application did not had good looking UI, so i made changes to use JQuery Mobile that makes building good looking UI much simpler. This is how my application looks like now
These are the steps that i followed
  1. Create a simple WorkLight application that invokes a SQL query you can use the steps mentioned in Connecting to Database from WorkLight
  2. First download the Worklight Starter Application for JQuery Mobile from Worklight Getting started page
  3. Expand the WorklightStarter_jQueryMobile.zip some where on your local disk
  4. Copy jquery.mobile*.js and jquery-*.js from the WorklightStarter_jQueryMobile.zip to the js folder of your application, Also copy jquery.mobile.*.css into css folder of your application
  5. Change the html page of your application to include the JQuery related css and js, this is how the html page looks for me
    
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8" />
    <meta name="viewport"
      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0" />
    <title>HelloDatabase</title>
    <link rel="shortcut icon" href="images/favicon.png" />
    <link rel="apple-touch-icon" href="images/apple-touch-icon.png" />
    <link rel="stylesheet" href="css/reset.css" />
    <link rel="stylesheet" href="css/HelloDatabase.css" />
    <link rel="stylesheet" href="css/jquery.mobile-1.0.min.css" />
    
    <script src="js/jquery-1.7.1.min.js"></script>
    <script>
      var jq = jQuery.noConflict();
    </script>
    
    <script src="js/jquery.mobile-1.0.min.js"></script>
    </head>
    <body onload="WL.Client.init({})" id="content" style="display: none">
     
      <div data-role="page" id="page1">
        <div data-theme="a" data-role="header">
          <h3>Contact DB App</h3>
        </div>
        <div data-role="content">
        
          <div data-role="fieldcontain">
                        <fieldset data-role="controlgroup">
                            <label for="textinput1">
                               First Name
                            </label>
                            <input id="contactName" placeholder="" value="" type="text" />
                        </fieldset>
                    </div>
                    <a data-role="button" data-transition="fade" href="javascript:getContact()" id="searchContact">
                        Search Contact
                    </a>
          <ul data-role="listview" data-inset="true" data-filter="true" id="displayContact">
            
          </ul>
    
        </div>
        <div data-theme="a" data-role="footer">
          <h3>Copyright stuff</h3>
        </div>
      </div>
     
    
      <script src="js/HelloDatabase.js"></script>
      <script src="js/messages.js"></script>
      <script src="js/auth.js"></script>
    </body>
    </html>
    
    In the head section first you should include jquery related css and js and also call var jq = jQuery.noConflict(); so that the jQuery $ character does not conflict with $ used by the prototype javascript framework used by worklight. Next use the jquery mobile template in the body section that divided the page into head, content and footer section.
  6. Add following code to the javascript file for your application
    
    function wlCommonInit(){
      // Common initialization code goes here
    }
    
    
    function getContact(){
      console.log("Entering getContact()");
    
      var contactName = '%'+$('contactName').getValue()+'%';
    
      var invocationData = {
          adapter:"mySQLAdapter",
          procedure:"searchContactByFirstName",
          parameters:[contactName]
      }
      var options ={
          onSuccess:loadContactSuccess,
          onFailure:loadContactFailure
      }
      
      WL.Client.invokeProcedure(invocationData, options);
    }
    
    function loadContactSuccess(result){
      console.log("Inside loadContactSuccess " + result);
      var html = '';
      if(result.invocationResult.isSuccessful){
        var contactList = result.invocationResult.resultSet;
        var i = 0;
        for(i =0 ; i < contactList.length ; i++){
          var currentContact = contactList[i];
          html =  html + '<li><a href="#">'+currentContact.FIRSTNAME +' ' 
       +currentContact.LASTNAME +'</a></li>';
        }
      }
      jq("#displayContact").html(html);
      jq("#displayContact").listview('refresh');
    }
    
    function loadContactFailure(result){
      console.log("Inside loadContactError " + result);
    }
    
    As you can can see i am using jq("#displayContact")> instead of regular $("#displayContact") this is the nonconflict version of JQuery that you must use in the WorkLight, but your still allowed to use the prototype based syntax for looking up objects as well like i did in $('contactName').getValue()

Debugging problems with worklight database access

In the Connecting to Database from WorkLight entry i developed a simple application to demonstrate how to connect to a database from Worklight, when i was developing that application i used these tools to debug. It seems that when i make a DB call using WL.Client.invokeProcedure() method it makes REST call and gets the response back in JSON format, i used the firebug tool to see what is being passed in and out. This is what data gets passed to the server
This is the response of the server that contains the response data in JSON format.The response in green displays what happens in case of success and the response with red boundary displays what happens in case of error
On the server side after deploying adapter i looked at the Worklight\server\log\server\server.log file to get detailed information about the errors and Worklight\server\log\server\error.log for short information about the errors

Connecting to Database from WorkLight

I wanted to figure out how to use SQL Adapter provided by WorkLight to create application that talks with database, with the difference that i want to access Apache Derby instead of MySQL that is used by WorkLight, so i built this simple application that takes contactId as input then use it to execute SELECT * from CONTACT where CONTACTID=contactId query and display the result.
I followed these steps to build my application
  1. First i did open the Worklight\server\conf\worklight.properties file in the text editor and i did add a section to define the JDBC connection parameters for connecting to Derby at the end of the file like this
    
    training-jndi-name=${custom-db.1.jndi-name}
    custom-db.1.relative-jndi-name=jdbc/worklight_training
    custom-db.1.driver=org.apache.derby.jdbc.ClientDriver
    custom-db.1.url=jdbc:derby://localhost:1527/C:/data/contact
    custom-db.1.username=dbadmin
    custom-db.1.password=dbadmin
    
  2. Then i did copy the derbyclient.jar which is JDBC driver for Apache Derby in the Worklight\server\lib folder, when i was copying the derbyclient.jar i noticed that, the same directory also has the mysql-connector-java-*.jar that worklight needs for its own database connectivity
  3. After that i had to restart the server for my changes to take effect
  4. Next i did create mySQLAdapter project by following the instructions on Creating SQL Adapters
  5. I changed the mySQLAdapter-impl.js like this
    
    var procedure1Statement = WL.Server.createSQLStatement("select * from CONTACT where CONTACTID = ?");
    function procedure1(param) {
      return WL.Server.invokeSQLStatement({
        preparedStatement : procedure1Statement,
        parameters : [param]
      });
    }
    
  6. Then i did use the following mySQLAdapter.xml
    
    <?xml version="1.0" encoding="UTF-8"?>
    <wl:adapter name="mySQLAdapter"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns:wl="http://www.worklight.com/integration"
      xmlns:sql="http://www.worklight.com/integration/sql">
    
      <displayName>mySQLAdapter</displayName>
      <description>mySQLAdapter</description>
      <connectivity>
        <connectionPolicy xsi:type="sql:SQLConnectionPolicy">
          <!-- Replace 'data-source-jndi-name' with the jndi name as defined in the data source. -->
          <!-- Example using jndi name: java:/comp/env/jdbc/ProjectDS 
             or using a place holder: ${project.db.jndi-name}       -->
             
          <dataSourceJNDIName>${training-jndi-name}</dataSourceJNDIName>
        </connectionPolicy>
        <loadConstraints maxConcurrentConnectionsPerNode="5" />
      </connectivity>
    
        <!-- Replace this with appropriate procedures -->
        <procedure name="procedure1"/>
    </wl:adapter>
    
  7. Once the adapter was ready i did deploy it on the server making sure that the deployment was successful
  8. Then i did create HelloDatabase application in the same project that has the adapter and i changed the main html to look like this
    
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1.0,
      maximum-scale=1.0, minimum-scale=1.0, user-scalable=0" />
            <title>HelloDatabase</title>
            <link rel="shortcut icon" href="images/favicon.png" />
            <link rel="apple-touch-icon" href="images/apple-touch-icon.png" />
            <link rel="stylesheet" href="css/reset.css" />
            <link rel="stylesheet" href="css/HelloDatabase.css" />        
        </head>
    
        <body onload="WL.Client.init({})" id="content" style="display: none">
         <table>
          <tr>
           <td>Contact Id</td>
           <td><input type="text" name="contactId" id="contactId"/></td>
          </tr>
          <tr>
           <td><button onclick="getContact()" title="GetContact" 
        label="GetContact">GetContact</button></td>
          </tr>
         </table>
         <div id="displayContact">
         
         </div>
         
            <script src="js/HelloDatabase.js"></script>
            <script src="js/messages.js"></script>
            <script src="js/auth.js"></script>
        </body>
    </html>
    
  9. Last step was to change the HelloDatabase.js like this
    
    function wlCommonInit(){
      // Common initialization code goes here
    }
    
    function getContact(){
      
      
      var contactId = $("contactId").getValue();
      console.log("Contact id " + contactId);
      var invocationData = {
          adapter:"mySQLAdapter",
          procedure:"procedure1",
          parameters:[contactId]
      }
      var options ={
          onSuccess:loadContactSuccess,
          onFailure:loadContactFailure
      }
      
      WL.Client.invokeProcedure(invocationData, options);
    }
    
    function loadContactSuccess(result){
      console.log("Inside loadContactSuccess " + result);
      console.log(result.invocationResult.resultSet[0].FIRSTNAME)
      $("displayContact").innerHTML = result.invocationResult.resultSet[0].FIRSTNAME + " " 
      + result.invocationResult.resultSet[0].LASTNAME +" " 
      + result.invocationResult.resultSet[0].EMAIL;
    }
    
    function loadContactFailure(result){
      console.log("Inside loadContactError " + result);
    }
    

Enabling debug/log console in Worklight

Recently i started learning about the IBM WorkLight and i followed the instructions on the Your First application to build a simple HelloWorld type of application. As a developer one of the first thing that i like to figure out how the application is actually working so i wanted to figure out a way to debug/enable log for worklight, and i followed these steps
  1. WOrklight generates log information as well as it allows you to use the same logger to write your own log information, How the log information is displayed depends on the client. For example in case of desktop client you can ask Worklight to display the log in a popup window by calling WL.Client.init({showLogger:true}); JavaScript method during onload event
  2. If you want you can use the WorkLight logger to write application specific log messages in the same logger you can do that by calling WL.Logger.debug("Sample debug statement"); WL.Logger.error("Sample error statement");
With these changes, this is how the wlCommonInit() method of my application looks like

function wlCommonInit(){
 console.log("Entering wlCommonInit");
 WL.Client.init({showLogger:true});
 WL.Logger.debug("Sample debug statement");
 WL.Logger.error("Sample error statement");
 console.log("Exiting wlCommonInit");
}
Now when i access the application through browser a logger windows gets popped up and it has the log messages like these

Setting up Worklight development environment

I want to learn about Worklight which is mobile application development platform that you can use for developing HTML5, native and hybrid applications. So i decided to install it on my machine and i followed these steps
  1. First i did go to Worklight Evaluation Version Download Page and i did download all the software listed on the page
  2. I followed the same steps mentioned in the document to install it on my Windows XP machine, The first time i installed MySQL on my machine i did not follow the MySQL Configuration Guide for Windows and my Worklight server installation failed to start on the first page where it asks for the MySQL connection information. So i did have to reconfigure it to use the steps mentioned in the MySQL Configuration Guide for Windows guide. I think unless you disable Strict Mode the WorkLight server install does not work.
Besides that installing the WorkLight steps on the document works pretty well.
In the How to either publish or consume message using STOMP in ActiveMQ entry i talked about how to use STOMP protocol for both publishing and consuming messages. I wanted to check if i can mix JMS + STOMP together, so i changed the sample application to use JMS API for publishing a message and use the STOMP for consuming messages, this works because no matter which API you use for communicating with the broker the message gets stored in the same messaging provider same this while consuming messages. You can download the sample code from here First configure your ActiveMQ so that it supports both JMS and STOMP connectors like this

<transportConnectors>
 <transportConnector name="openwire" uri="tcp://localhost:61616?trace=true"/>
 <transportConnector name="stomp" uri="stomp://localhost:61613?trace=true"/>
</transportConnectors>
Then create a jndi.properties file that defines the ConnectionFactory and Queue in the JNDI context for your application like this

java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory
java.naming.provider.url = tcp://localhost:61616
java.naming.security.principal=system
java.naming.security.credentials=manager
connectionFactoryNames = QueueCF
queue.stomptest=stomptest
This jndi.properties file makes sure that the objects of ConnectionFactory and Queue and bound in the JNDI context so that your java code remains JMS compliant with no reference to ActiveMQ. Then create OpenWireMessagePublisher.java like this

package com.webspherenotes.stomp;

import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class OpenWireMessagePublisher {
  public static void main(String[] argv){
    try {
      InitialContext context = new InitialContext();
      QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory)context.lookup("QueueCF");
      QueueConnection queueConnection = queueConnectionFactory.createQueueConnection();
      QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
      Queue queue = (Queue)context.lookup("stomptest");
      TextMessage textMessage = queueSession.createTextMessage();
      textMessage.setText("This is sample message for stomp queue");
      QueueSender queueSender = queueSession.createSender(queue);
      queueSender.send(textMessage);
      queueConnection.close();
    } catch (NamingException e) {
      e.printStackTrace();
    } catch (JMSException e) {
      e.printStackTrace();
    }
  }
}
The OpenWireMessagePublisher.java is using JMS API to publish a message to stomptest queue. Now lets create a StompMessageConsumer.java like this

package com.webspherenotes.stomp;
import java.io.IOException;
import java.net.UnknownHostException;
import org.apache.activemq.transport.stomp.StompConnection;
import org.apache.activemq.transport.stomp.StompFrame;
import org.apache.activemq.transport.stomp.Stomp.Headers.Subscribe;

public class StompMessageConsumer {
  public static void main(String[] args) {
    try {
      StompConnection connection = new StompConnection();
      connection.open("localhost", 61613);
      connection.connect("system", "manager");
      connection.subscribe("/queue/stomptest", Subscribe.AckModeValues.CLIENT);
      connection.begin("tx2");
      StompFrame message = connection.receive();
      System.out.println(message.getBody());
      connection.ack(message, "tx2");
      connection.commit("tx2");
      connection.disconnect();
    } catch (UnknownHostException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
The StompConsumer code does not care about if the message was published using JMS or STOMP it remains same.

How to either publish or consume message using STOMP in ActiveMQ

The ActiveMQ server supports Simple Text-oriented Messaging Protocol(STOMP) that we can use for communicating between client and server. I wanted to try out this feature so i built a sample application that has two classes one is StompMessagePublisher.java that publishes a message using STOMP and StompMessageConsumer that consumes a message. You can download the sample application from here By default the STOMP connector is disabled in the ActiveMQ so first thing that you would have to do is enable it. First open <activemq_installroot>\conf\activemq.xml file and find the transportConnectors element by default it will have only one transportConnector child element with name equal to openwire add stomp element in it like this

<transportConnectors>
 <transportConnector name="openwire" uri="tcp://localhost:61616?trace=true"/>

 <transportConnector name="stomp" uri="stomp://localhost:61613?trace=true"/>

</transportConnectors>
Then create a StompMessagePublisher.java like this

package com.webspherenotes.stomp;

import java.io.IOException;
import java.net.UnknownHostException;

import org.apache.activemq.transport.stomp.StompConnection;
public class StompMessagePublisher {

  public static void main(String[] args) {
    try {
      StompConnection connection = new StompConnection();
      connection.open("localhost", 61613);
      connection.connect("system", "manager");
       connection.begin("tx1");
      connection.send("/queue/stomptest", "This is test message 1");
      connection.commit("tx1");
      connection.disconnect();
    } catch (UnknownHostException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
In this class first we are opening a StompConnection with localhost:61613, after establishing connection we are sending message to stomptest queue in a transaction Next create StompMessageConsumer.java class which looks like this

package com.webspherenotes.stomp;

import java.io.IOException;
import java.net.UnknownHostException;

import org.apache.activemq.transport.stomp.StompConnection;
import org.apache.activemq.transport.stomp.StompFrame;
import org.apache.activemq.transport.stomp.Stomp.Headers.Subscribe;

public class StompMessageConsumer {

  public static void main(String[] args) {
    try {
      StompConnection connection = new StompConnection();
      connection.open("localhost", 61613);
      connection.connect("system", "manager");
      connection.subscribe("/queue/stomptest", Subscribe.AckModeValues.CLIENT);
      connection.begin("tx2");
      StompFrame message = connection.receive();
      System.out.println(message.getBody());
      connection.ack(message, "tx2");
      connection.commit("tx2");
      connection.disconnect();
    } catch (UnknownHostException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
In the StompMessageConsumer.java, first i am establishing STOMP connection to the localhost and then subscribing to stomptest queue, after subscribing to the queue we have to call the receive() method on the connection to receive the message from the queue.

How to use ActiveMQ in Jetty

I wanted to figure out how to use Apache ActiveMQ in a web application that is running in Jetty, Also i wanted to use the Maven Jetty Plugin so i built this sample application which contains a , when i make GET request to servelt it takes value of message query parameter and publishes it as a TextMessage to a Queue, you can download the source code for the sample application from here First thing that i did is create a pom.xml file that looks like this

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.webspherenotes.jms</groupId>
  <artifactId>HelloJettyActiveMQ</artifactId>
  <version>1.0</version>
  <packaging>war</packaging>
  <name>HelloJettyActiveMQ</name>
  <description>Sample app to demonstrate how to use 
  ActiveMQ in Jetty</description>
  <dependencies>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.4</version>
    </dependency>
    <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-core</artifactId>
      <version>5.5.0</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.5.11</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jms</artifactId>
      <version>3.0.3.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.apache.xbean</groupId>
      <artifactId>xbean-spring</artifactId>
      <version>3.9</version>
    </dependency>
  </dependencies>
  <build>
    <finalName>HelloJettyActiveMQ</finalName>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
   
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>7.2.2.v20101205</version>
        <configuration>
          <scanIntervalSeconds>10</scanIntervalSeconds>
          <webAppConfig>
            <jettyEnvXml>${basedir}/src/main/resources/jetty-env.xml</jettyEnvXml>
          </webAppConfig>
        </configuration>
      </plugin>
   
    </plugins>
  </build>
</project>
I am using version 7.2.2 of Jetty server in the jetty-maven-plugin, also note that i configured a jetty-env.xml file which defines the JMS resources in the JNDI context. This is how my jetty-env.xml file looks like

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" 
"http://jetty.mortbay.org/configure.dtd">
<Configure id='jms-webapp-wac' class="org.eclipse.jetty.webapp.WebAppContext">
  <New id="connectionFactory" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg>
      <Ref id='jms-webapp-wac' />
    </Arg>
    <Arg>jms/ConnectionFactory</Arg>
    <Arg>
      <New class="org.apache.activemq.ActiveMQConnectionFactory">
        <Arg>tcp://localhost:61616</Arg>
      </New>
    </Arg>
  </New>
  <New id="fooQueue" class="org.eclipse.jetty.plus.jndi.Resource">
    <Arg>jms/FooQueue</Arg>
    <Arg>
      <New class="org.apache.activemq.command.ActiveMQQueue">
        <Arg>FOO.QUEUE</Arg>
      </New>
    </Arg>
  </New>
</Configure>
The jetty-env.xml file defines 2 resources on is the ActiveMQConnectionFactory and second is the ActiveMQQueue. After that i did declare the messaging related resources in web.xml, so my web.xml file looks like this

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
         http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">  
  <display-name>HelloEmbeddedServer</display-name>
  <servlet>
    <servlet-name>MessagePublishingServlet</servlet-name>
    <servlet-class>com.webspherenotes.jms.MessagePublishingServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>MessagePublishingServlet</servlet-name>
    <url-pattern>/MessagePublishingServlet/*</url-pattern>
  </servlet-mapping>
  
  
  <resource-ref>
    <description>JMS Connection</description>
    <res-ref-name>jms/ConnectionFactory</res-ref-name>
    <res-type>javax.jms.ConnectionFactory</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Shareable</res-sharing-scope>
  </resource-ref>
  
  <message-destination-ref>
    <message-destination-ref-name>jms/FooQueue</message-destination-ref-name>
    <message-destination-type>javax.jms.Queue</message-destination-type>
    <message-destination-usage>Produces</message-destination-usage>
    <message-destination-link>jms/FooQueue</message-destination-link>
  </message-destination-ref>
 
 
</web-app>
This is how my MessagePublishingServlet.java looks like

package com.webspherenotes.jms;

import java.io.IOException;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MessagePublishingServlet extends HttpServlet{
  Logger logger = LoggerFactory.getLogger(MessagePublishingServlet.class);
  Connection connection;
  Queue queue;
  

  @Override
  public void init() throws ServletException {
    logger.debug("Entering MessagePublishingServlet.init()");
    try {
      InitialContext context = new InitialContext();
      ConnectionFactory connectionFactory = (ConnectionFactory)context.lookup("java:comp/env/jms/ConnectionFactory");
      logger.debug("Connection Factory " + connectionFactory);
      connection = connectionFactory.createConnection();
      queue =(Queue) context.lookup("jms/FooQueue");
      logger.debug("After looking up the queue " + queue); 
    } catch (Exception e) {
      logger.error("Error occured in MessagePublishingServlet.init() " + e.getMessage(),e);
    }
    logger.debug("Exiting MessagePublishingServlet.init()");

  }

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    logger.debug("Entering MessagePublishingServlet.doGet()");
    resp.setContentType("text/html");
    resp.getWriter().println("Hello from MessagePublishingServlet.doGet()");
    try {

      Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
      TextMessage textMessage = session.createTextMessage();
      textMessage.setText(req.getParameter("message"));
      MessageProducer queueSender = session.createProducer(queue);
      queueSender.send(textMessage); 
    } catch (JMSException e) {
      logger.error("Error occured in MessagePublishingServlet.doGet() " + e.getMessage(),e);

    }
    logger.debug("Exiting MessagePublishingServlet.doGet()");
  }

}
The init() method looks up the JMS objects from the InitialContext, in the doGet() method i am reading the value of message query parameter and using it to send a TextMessage.

Using Spring message pojo

The Spring Framework has concept of message driven pojo's which are similar to MDB that you can use for receiving messages asynchronously. I wanted to try that out so i changed the sample application that i developed in Using amq namespace for building Spring JMS application for ActiveMQ post. In my sample application i did create a simple MessageListener class that gets called whenever there is a message, you can download the source code for sample application from here First i did create a simple MessageListener POJO class like this

package com.webspherenotes.jms;

public class MessageListener {

  public void handleMessage(String message){
    System.out.println("Inside MessageListener.handleMessage() " 
 + message);
  }
}
The handleMessage() method of the MessageListener will get called whenever the message is available. Next define the message listener class in the spring configuration like this.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:jms="http://www.springframework.org/schema/jms"
  xmlns:amq="http://activemq.apache.org/schema/core"
  xsi:schemaLocation="http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.5.0.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

  <amq:connectionFactory id="connectionFactory"
    brokerURL="tcp://localhost:61616" />

  <bean id="jmsTemplate" 
  class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="connectionFactory" />
    <property name="defaultDestinationName" value="queue1" />

  </bean>


  <bean id="messageListener" 
  class="com.webspherenotes.jms.MessageListener" />
  
  <jms:listener-container connection-factory="connectionFactory">
    <jms:listener destination="queue1" ref="messageListener" 
 method="handleMessage"/>
  </jms:listener-container>
</beans>

Now when you run the publisher mvn exec:java -Dexec.mainClass=com.webspherenotes.jms.MessagePublisher it will initialize the spring context and as part of that process it will create MessageListner class and attach it as listener to the destination, so when the message gets published your MessageListner will get called automatically to handle/consume the message.

Maven build file(pom.xml) for Spring Active MQ JMS application

In the Using amq namespace for building Spring JMS application for ActiveMQ entry i built a sample Spring Active MQ JMS application, this is the maven pom.xml file for it.

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.webspherenotes.jms</groupId>
  <artifactId>HelloSpringActiveMQ</artifactId>
  <version>1.0</version>
  <name>HelloSpringActiveMQ</name>
  <description>Sample Spring ActiveMQ JMS application</description>
  <dependencies>
    <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-core</artifactId>
      <version>5.5.0</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.5.11</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jms</artifactId>
      <version>3.0.3.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.apache.xbean</groupId>
      <artifactId>xbean-spring</artifactId>
      <version>3.9</version>
    </dependency>
  </dependencies>
</project>
Once my pom.xml is ready i can use following commands to run MessagePublisher.java and MessageReceiver.java
  1. mvn exec:java -Dexec.mainClass=com.webspherenotes.jms.MessagePublisher
  2. mvn exec:java -Dexec.mainClass=com.webspherenotes.jms.MessageReceiver

Using amq namespace for building Spring JMS application for ActiveMQ

Using amq namespace makes developing Spring application for ActiveMQ very easy, i wanted to try that so i built this sample application, This is how my applicationContext.xml file looks like

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:jms="http://www.springframework.org/schema/jms"
  xmlns:amq="http://activemq.apache.org/schema/core"
  xsi:schemaLocation="http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.5.0.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

  <amq:connectionFactory id="connectionFactory"
    brokerURL="tcp://localhost:61616" />

  <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="connectionFactory" />
    <property name="defaultDestinationName" value="queue1" />
  </bean>

</beans>
As you can see i have only two beans one for ConnectionFactory and other for JmsTemplate. This is how my MessagePublisher.java looks like

package com.webspherenotes.jms;

import java.util.Date;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

public class MessagePublisher {
  public static void main(String[] args)throws Exception {
    ApplicationContext context = 
 new ClassPathXmlApplicationContext("applicationContext.xml");
    JmsTemplate jmsTemplate =(JmsTemplate) context.getBean("jmsTemplate");
    MessageCreator message = new MessageCreator() {
      public Message createMessage(Session session) throws JMSException {
        TextMessage textMessage = session.createTextMessage();
        String messageStr = "This message is sent using MessageCreator" + new Date();
        textMessage.setText(messageStr);
        return textMessage;
      }
    };
    jmsTemplate.send(message);
  }
}
This is how my MessageReceiver class looks like

package com.webspherenotes.jms;

import javax.jms.TextMessage;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;

public class MessageReceiver {
  public static void main(String[] args)throws Exception {
    ApplicationContext context = 
    new ClassPathXmlApplicationContext("applicationContext.xml");
    JmsTemplate jmsTemplate =(JmsTemplate) context.getBean("jmsTemplate");
    TextMessage message = (TextMessage)jmsTemplate.receive();
    System.out.println("Message received " + message.getText());
  }
}
This is sample of how to wait for message synchronously.

Apache Maven pom.xml for activemq standalone application

I wanted to check what pom.xml should i use to create ActiveMQ publisher and consumer in standalone java application so i built a sample application, that you can download from here First i had to use the following directory structure
Then i did use the following pom.xml, only dependencies i have is on activemq-core, and slf4j-log4j and it takes care of downloading necessary jars

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.webspherenotes.jms</groupId>
  <artifactId>HelloActiveMQMaven</artifactId>
  <version>1.0</version>
  <name>HelloActiveMQMaven</name>
  <description>How to use ActiveMQ in Maven </description>
  <dependencies>
    <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-core</artifactId>
      <version>5.5.0</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.6.4</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.1.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>java</goal>
            </goals>
            <configuration>
              <mainClass>
     com.webspherenotes.jms.HelloActiveMQPublisher</mainClass>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>
Then i can execute the publisher by executing mvn exec:java -Dexec.mainClass=com.webspherenotes.jms.HelloActiveMQPublisher and i can execute the consumer by executing mvn exec:java -Dexec.mainClass=com.webspherenotes.jms.HelloActiveMQConsumer

Embed ActiveMQ using Java Code

You can use embedded ActiveMQ which means you can create object of BrokerService and then use java code to configure it instead of regular approach of using activemq.xml file, i wanted to try that so i did create this sample application which you can download from here First create HelloEmbeddedBrokerService class like this, in this class i am just creating object of BrokerService, after that you can call methods to configure it and once your done call brokerService.start() to start the broker.

package com.webspherenotes.jms;

import org.apache.activemq.broker.BrokerService;

public class HelloEmbeddedBrokerService {

  public static void main(String[] args) {
    try {

      BrokerService brokerService = new BrokerService();
      brokerService.addConnector("tcp://localhost:61616");
      brokerService.start();

    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
Then use the jndi.properties file like this to configure JNDI context for the JMS client code

java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory
java.naming.provider.url = tcp://localhost:61616
java.naming.security.principal=system
java.naming.security.credentials=manager
connectionFactoryNames = QueueCF
queue.SampleQ = jms.SampleQ
This is how the code for the message publisher would look like, as you can see your client code does not care how the message broker is started.

package com.webspherenotes.jms;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;

import org.apache.activemq.ActiveMQConnectionFactory;

public class HelloActiveMQPublisher {

  /**
   * @param args
   */
  public static void main(String[] args) throws Exception{
    InitialContext context = new InitialContext();
    ConnectionFactory connectionFactory = (ConnectionFactory)context.lookup("QueueCF");
    
    Connection connection = connectionFactory.createConnection();
      connection.start();
      
      Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
      
      Queue queue = (Queue)context.lookup("SampleQ");
      
      MessageProducer messageProducer = session.createProducer(queue);
      
      TextMessage textMessage = session.createTextMessage();
      textMessage.setText("Lets see if i can send messages using Embedded Broker");
      
      messageProducer.send(textMessage);

      connection.close();
  }

}

Using MessageAuthorizationPolicy in ActiveMQ

The ActiveMQ broker allows message level security, that means you can ask ActiveMQ to call your business logic before consuming every message, and as a result get control on which message can be consumed by which MessageListener. I wanted to try that, so i created this SimpleMessagePolicy.java class which checks if the message body contains Secrete message for clientId com.webspherenotes.secret text, if yes it checks if the consumers's caller Id is com.webspherenotes.secret if yes then only it will allow the consumer to consume message. You can download the sample code for SampleMessagePolicy from here First i had to create SampleMessagePolicy class that implements MessageAuthorizationPolicy interface.The isAllowedToConsume() method of your class gets before a consumer is trying to consume every message. Create this class in separate java project, compile that project and copy the .jar file in the activemq/lib directory

package com.webspherenotes.jms;

import javax.jms.JMSException;
import javax.jms.TextMessage;

import org.apache.activemq.broker.ConnectionContext;
import org.apache.activemq.command.Message;
import org.apache.activemq.security.MessageAuthorizationPolicy;

public class SampleMessagePolicy implements MessageAuthorizationPolicy {

  @Override
  public boolean isAllowedToConsume(ConnectionContext messageContext,
      Message message) {
    try {
      System.out
          .println("Inside SampleMessagePolicy.isAllowedToConsume() ");
      System.out.println("Client Id " + messageContext.getClientId());
      if (message instanceof TextMessage) {
        TextMessage textMessage = (TextMessage) message;
        System.out.println("Text message is " + textMessage.getText());

        String messageStr = textMessage.getText();
        if (messageStr
            .equals("Secrete message for clientId com.webspherenotes.secret")) {
          System.out
              .println("Secret message received check the clientId");
          if (messageContext.getClientId().equals(
              "com.webspherenotes.secret")) {
            System.out
                .println("Got request from com.webspherenotes.secret, for secret message returning message");
            return true;
          } else {
            System.out
                .println("Got request from some other client, for secret message returning, hidding message");
            return false;
          }
        } else {
          System.out
              .println("Non secret message received, returning message");
          return true;
        }
      }

    } catch (JMSException e) {
      e.printStackTrace();
    }

    return true;
  }

}
Next configure the ActiveMQ so that it will use SampleMessagePolicy as MessageAuthorizationPolicy like this

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:amq="http://activemq.apache.org/schema/core"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
  http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
  http://activemq.apache.org/schema/core 
  http://activemq.apache.org/schema/core/activemq-core.xsd
  http://activemq.apache.org/camel/schema/spring 
  http://activemq.apache.org/camel/schema/spring/camel-spring.xsd">

  <!-- Allows us to use system properties as variables in this configuration file -->
  <bean
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />

  <broker xmlns="http://activemq.apache.org/schema/core"
    brokerName="localhost" dataDirectory="${activemq.base}/data">


        <messageAuthorizationPolicy>
            <bean class="com.webspherenotes.jms.SampleMessagePolicy"
                xmlns="http://www.springframework.org/schema/beans" />
        </messageAuthorizationPolicy>

    <!-- The transport connectors ActiveMQ will listen to -->
    <transportConnectors>
      <transportConnector name="openwire"
        uri="tcp://localhost:61616" />
    </transportConnectors>

  </broker>

</beans>
After configuring the ActiveMQ restart the server for your changes to take effect. Then create MessageConsumer.java like this, in this file set the ClientId to com.webspherenotes.secret so that it will receive the secrete message.

package com.webspherenotes.jms;

import java.io.BufferedReader;
import java.io.InputStreamReader;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class MessageConsumer implements MessageListener{

  QueueConnection queueConnection;
  QueueSession queueSession;

  public MessageConsumer() {
    try {
      InitialContext context = new InitialContext();
      QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory) context
          .lookup("QueueCF");
      queueConnection = queueConnectionFactory.createQueueConnection("consumer","password");

      queueConnection.setClientID("com.webspherenotes.secret");
      queueSession = queueConnection.createQueueSession(false,
          Session.AUTO_ACKNOWLEDGE);
      Queue queue = (Queue) context.lookup("SampleQ");
      QueueReceiver queueReceiver = queueSession.createReceiver(queue);
      queueReceiver.setMessageListener(this);
      queueConnection.start();
    } catch (NamingException e) {
      e.printStackTrace();
    } catch (JMSException e) {
      e.printStackTrace();
    }
  }

  @Override
  public void onMessage(Message message) {
    try {
      TextMessage textMessage = (TextMessage) message;
      System.out.println("Inside MessageConsumer.onMessage "
          + textMessage.getText());
    } catch (JMSException e) {
      e.printStackTrace(System.out);
    }
  }

  public static void main(String[] argv) {
    try {
      MessageConsumer messageConsumer = new MessageConsumer();

      BufferedReader stdin = new BufferedReader(new InputStreamReader(
          System.in));
      System.out.println("Press enter to quit application");
      stdin.readLine();
      messageConsumer.queueConnection.close();

    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}

Using ActiveMQConnectionFactory for creating connection factory

When developing a messaging application for ActiveMQ, say for standalone client, normally we create a jndi.properties file like this in the source folder.

java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory
java.naming.provider.url = tcp://localhost:61616
java.naming.security.principal=system
java.naming.security.credentials=manager
connectionFactoryNames = QueueCF
queue.ActiveMQ = jms.ActiveMQ
After that we can look up both QueueCF and ActiveMQ from inside the code by looking them up in the InitialContext like this

InitialContext context = new InitialContext();
  
QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory)context.lookup("QueueCF");

QueueConnection queueConnection = queueConnectionFactory.createQueueConnection();
QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

Queue queue = (Queue)context.lookup("ActiveMQ");

Using the jndi.properties option makes your code JMS compliant, but you will have to define the queues and connection factories before hand, with ActiveMQ we have another option which is to use ActiveMQConnectionFactory like this, in this example first we create object of ActiveMQConnectionFactory by passing URL to the broker then we use session.createQueue("ActiveMQ") to create the Queue, It allows us to create Queues dynamically at run time.

package com.webspherenotes.jms;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;

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

      String brokerURL = "tcp://localhost:61616";
      ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerURL);

      Connection connection = connectionFactory.createConnection();
      connection.start();
      Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
      Queue queue = session.createQueue("ActiveMQ");
      MessageProducer messageProducer = session.createProducer(queue);
      TextMessage textMessage = session.createTextMessage();
      textMessage.setText("This is a message for dynamically create message q");
      messageProducer.send(textMessage);
      connection.close();
  }
}

package com.webspherenotes.jms;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;

public class HelloActiveMQConsumer implements MessageListener{

  public static void main(String[] args) throws Exception{
    String brokerURL = "tcp://localhost:61616";
    ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(brokerURL);
    Connection connection = connectionFactory.createConnection();
    connection.start();
    Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
    Queue queue = session.createQueue("ActiveMQ");
    MessageConsumer messageConsumer = session.createConsumer(queue);
    messageConsumer.setMessageListener(new HelloActiveMQConsumer());
    BufferedReader stdin = new BufferedReader(new InputStreamReader(
          System.in));
    System.out.println("Press enter to quit application");
    stdin.readLine();
    connection.close();
  }
  @Override
  public void onMessage(Message message) {
    try {
      TextMessage textMessage =(TextMessage)message;
      System.out.println("Thie message is " + textMessage.getText());
    } catch (JMSException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

Request/reply messaging using TopicRequestor

In the Request/Reply messaging using QueueSender , i tried out the QueueRequestor approach for request/reply messaging, similarly i wanted to try out the TopicRequestor, so i built this sample code First create a TopicRequestor class and use it for sending message, the control blocks at the topicRequestor.request() method till it gets response, Even if there are more than one consumer the request() method would return on the first response, rest of the responses would be ignored.

package com.webspherenotes.jms;

import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicPublisher;
import javax.jms.TopicRequestor;
import javax.jms.TopicSession;
import javax.naming.InitialContext;

public class SampleTopicRequestor {

  /**
   * @param args
   */
  public static void main(String[] args)throws Exception{
    InitialContext context = new InitialContext();
    
    TopicConnectionFactory topicConnectionFactory = (TopicConnectionFactory)context.lookup("TopicCF");
    
    TopicConnection topicConnection = topicConnectionFactory.createTopicConnection();
    
    TopicSession topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
    
    Topic topic = (Topic)context.lookup("topic1");
    
    TopicPublisher topicPublisher = topicSession.createPublisher(topic);
    
    TextMessage textMessage = topicSession.createTextMessage();
    textMessage.setText("Hello how are you doing?");
    
    TopicRequestor topicRequestor = new TopicRequestor(topicSession, topic);
    topicConnection.start();
    
    TextMessage replyMessage =(TextMessage) topicRequestor.request(textMessage);
    System.out.println("Topic response " + replyMessage.getText());

    topicConnection.close();
  }

}

On the consumer side the value of the replyTo header would be a temporary topic but i wanted to try out the generic Destination and MessageProducer for sending message.

package com.webspherenotes.jms;

import java.io.BufferedReader;
import java.io.InputStreamReader;

import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class SampleTopicConsumer implements MessageListener {
  
  TopicConnection topicConnection;
  TopicSession topicSession;

  public SampleTopicConsumer() {
    try {
      InitialContext context = new InitialContext();

      TopicConnectionFactory topicConnectionFactory = (TopicConnectionFactory) context
          .lookup("TopicCF");

       topicConnection = topicConnectionFactory
          .createTopicConnection();

      topicSession = topicConnection.createTopicSession(false,
          Session.AUTO_ACKNOWLEDGE);

      Topic topic = (Topic) context.lookup("topic1");
      
      TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic);
      
      topicSubscriber.setMessageListener(this);
      topicConnection.start();
    } catch (NamingException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (JMSException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
  
  

  @Override
  public void onMessage(Message message) {
    try {
      TextMessage textMessage =(TextMessage)message;
      System.out.println("The message is " + textMessage.getText());

      Destination replyToDestination = textMessage.getJMSReplyTo();
      MessageProducer messageProducer = topicSession.createProducer(replyToDestination);
      
      TextMessage replyMessage = topicSession.createTextMessage();
      replyMessage.setText("Reply message to " + textMessage.getText());
      messageProducer.send(replyMessage);
      System.out.println( textMessage.getJMSReplyTo());

    } catch (JMSException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    
  }



  /**
   * @param args
   */
  public static void main(String[] args) throws Exception {
    SampleTopicConsumer sampleTopicConsumer = new SampleTopicConsumer();
    BufferedReader stdin = new BufferedReader(new InputStreamReader(
        System.in));
    System.out.println("Press enter to quit application");
    stdin.readLine();
    sampleTopicConsumer.topicConnection.close();
  }

}