Thursday, April 17, 2014

JACOCO as a coverage tool for Unit testing, Integration testing and Functional testing

JACOCO as a coverage tool for Unit testing, Integration testing and Functional testing
This article explains how to generate coverage reports for unit testing,integration testing and functional testing using JACOCO.
Instrumentation
Ability to alter byte code through classloaders for the purpose of gathering data such as profiling, coverage etc. is known as instrumentation. Instrumentation was introduced in 1.5.
JACOCO 
JACOCO is one of the most popular JAVA Coverage tool used in the industry. Using on the fly instrumentation, JACOCO will modify the byte code by inserting its hooks to record the coverage information making the integration with build tools, server simple. Through this feature, application code remains clean. Thanks to the instrumentation feature added in JDK 1.5!!!
 Technologies used
  1. Java 1.7
  2. Jboss AS 7.2
  3. Maven
  4. Spring 4.0.3
  5. JACOCO  0.6.4 
Overview of Classes
UserDao.java A simple DAO to save,read users from DB
UserService.java A simple service with an handle to DAO
UserController.java A simple REST interface

and the flow is given below


 Below is the code snippet from UserDao.java to save users

 @Override
    public void saveUsers(final List users) {
        getJdbcTemplate().batchUpdate(SQLConstants.SAVE_USERS.getValueAsString(), new BatchPreparedStatementSetter() {

            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                IUser user = users.get(i);
                ps.setString(1, user.getUserName());
                ps.setString(2, user.getPassword());
                ps.setBoolean(3, user.isAcceptTerms());
                ps.setString(4, user.getFirstName());
                ps.setString(5, user.getLastName());
                ps.setString(6, user.getMiddleName());
                if(user.getRegisteredOn() == null){
                    user.setRegisteredOn(Calendar.getInstance());
                }
                ps.setTimestamp(7, new Timestamp(user.getRegisteredOn().getTimeInMillis()));
                ps.setInt(8, user.getAge());
            }

            @Override
            public int getBatchSize() {
                return users.size();
            }
        });
    }

Below the code snippet from UserDaoTest.java

 @Test
    @Rollback(true)
    public void testSaveUsers(){
       IUser user = new User();
       user.setUserName("ïtsvenkis");
       user.setPassword("itsvenkis");
       user.setAge(28);
       user.setRegisteredOn(Calendar.getInstance());
       user.setAcceptTerms(true);
       user.setFirstName("Venkat");
       user.setLastName("Nanda");
       List users = new ArrayList();
       users.add(user);
       getUserDao().saveUsers(users);
    }

Specify JACOCO Maven plugin in pom.xml 


                org.jacoco
                jacoco-maven-plugin
                0.7.0.201403182114
                
                    ${basedir}/target/coverage-reports/jacoco.exec
                    ${basedir}/target/coverage-reports/jacoco.exec
                    
                
                
                    
                        jacoco-initialize
                        
                            prepare-agent
                        
                    
                    
                        jacoco-site
                        package
                        
                            report
                        
                    
                
            
            

 
Now running the maven build with install and package will generate a nice coverage report as shown below for all the unit tests.
 


While this looks simple, it gets little tricky when we have a bunch of tests cases to verify the functionality of an application. In real world one may have their application deployed on a server and  functional test suites will run against the server. JACOCO agent can be added as an JVM option in the application server and on the fly instrumentation will kick in enabling coverage information. All the coverage information will be collected in exec file and reports can be generated from this file.


 

set "JAVA_OPTS=%JAVA_OPTS% -javaagent:c:\apps\jacoco\lib\jacocoagent.jar=destfile=c:\apps\reports\jacoco.exec,append=true,output=file"

Start the server and execute the test suites or execute some manual requests and stop the server once all the testing is done. JACOCO will dump the coverage information on JVM exit.
Below is the coverage report generated

Source Code github . Downlaod JACOCO-COVERAGE Project.

Friday, February 7, 2014

HornetQ-Spring integration tutorial


What is HORNETQ?
HORNETQ is the default messaging system in JBOSS application server. It is an open source project used to build clustered, and asynchronous messaging system. More information can be found here. In my old blog posts I discussed about basic concepts such as how to create users to consume and produce messages in the messgaing system, and REST interface support . Please find tutorials below
  1.  HORNETQ- JMS REST tutorial
  2. HORNETQ JMS Tutorial  
While the above tutorial discuss about how to use HORNETQ through REST and JMS API, this tutorial will focus on how to integrate the highly scalable messaging system with Spring JMS module and the advantages one gets by doing so.
Technologies used in this tutorial are given below
  1. Spring 3.2
  2. JBOSS eap-6.1
  3. Maven
  4. HORNETQ 2.3.1
NOTE:Before getting starting create users,queues as shown in this post.
Spring-JMS has many advantages
  1. Avoid repetitive code
  2. Easy maintenance
  3. Exception translation etc.
This tutorial can be mainly divided into three parts. First we will try to produce a message to the queue. Second we will consume it through spring JMS template. Third we will have a simple POJO to consume the message.A simple POJO to consume a message!!! How cool is that!!! Thanks to spring-jms module.
Below is the controller which will be used to produce messages. For simplicity sake we will create a TextMessage and push it to the queue
package com.blogspot.itsvenkis;

import org.apache.log4j.Logger;
import org.springframework.http.MediaType;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.jms.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * User: itsvenkis
 * Date: 07/02/14
 */

@Controller
@RequestMapping(value ="/spring-jms")
public class SpringJmsController {

    private JmsTemplate jmsTemplate;
    private Logger logger = Logger.getLogger(SpringJmsController.class);

    public JmsTemplate getJmsTemplate() {
        return jmsTemplate;
    }

    public void setJmsTemplate(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    private Queue ticketQueue;
    public Queue getTicketQueue() {
        return ticketQueue;
    }

    public void setTicketQueue(Queue ticketQueue) {
        this.ticketQueue = ticketQueue;
    }

    @RequestMapping(value = "/produce-me", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public void saveMessage( HttpServletRequest request, HttpServletResponse response) throws IOException, JMSException {
         getJmsTemplate().send(getTicketQueue(),new MessageCreator() {
             @Override
             public Message createMessage(Session session) throws JMSException {
                 return session.createTextMessage("Hello Spring JMS!!!");
             }
         });
         logger.info("Sent message to the queue ....");
         response.setStatus(HttpServletResponse.SC_ACCEPTED);
    }

    @RequestMapping(value = "/consume-me", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public void consumeMessage(HttpServletRequest request, HttpServletResponse response) throws JMSException {
        TextMessage message = (TextMessage) getJmsTemplate().receive(getTicketQueue());
        logger.info("Received message "+message.getText());
    }

}

ConnectionFactory consists of various connection configuration parameters as defined by the admin user. A client i.e. SpringJMSTemplate uses it to create connections to the destinations. ConnectionFactories and destinations i.e. Queues/Topics are defined in standalone-full.xml . Below is the code snippet from standalone-full.xml

            
                true
                NIO
                2

                
                    
                    
                        
                    
                    
                

                
                    
                    
                        
                        
                    
                    
                

                
                    
                        
                        
                        
                        
                        
                        
                        
                    
                

                
                    
                        jms.queue.DLQ
                        jms.queue.ExpiryQueue
                        0
                        10485760
                        BLOCK
                        10
                    
                

                
                    
                        
                            
                        
                        
                            
                        
                    
                    
                        
                            
                        
                        
                            
                        
                    
                    
                        
                        
                            
                        
                        
                            
                        
                    
                

                
                    
                        
                    
                
            
        

Kindly note that ConnectionFactories are exposed as JNDI objects.We can use JNDI-lookups to get the ConenctionFactory in our spring application context. Below is the code snippet of applicationContext.xml


    
    

    
        
        
        
    

    
    

    
    

    
       
    

    
    


Doing a POST request to http://localhost:8080/spring-hornetq/spring-jms/produce-me will produce a message and push it to 'ticketOrderQueue'

The receipt of this message can be confirmed from the below screenshot
Let us do a GET request to http://localhost:8080/spring-hornetq/spring-jms/consume-me to consume the message.

Log messages
While everything is good so far!!! Dont you see a big disadvantage with this approach? Consuming message through an explicit GET request. Well!!! JMS is all about asynchronous message processing. So we would like to react to a message in the queue rather than doing a polling. In my previous blog posts you can notice that I used message driven beans to consume the message asynchronously.
Message Driven Beans was included in EJB 2 specification.Basically MDBs are EJBs that process messages asynchronously. With EJB 3 specification, we can just implement MessageListener interface for asynchronous processing. Spring-JMS module has its own implementation of MessageDriven beans by which we can convert a simple POJO to process the messages asynchronously. Below is the code snippet of our POJO
package com.blogspot.itsvenkis.mdp;


import org.apache.log4j.Logger;

/**
 * User: itsvenkis
 * Date: 07/02/14
 */
public class TicketQueueConsumer {
    private Logger logger = Logger.getLogger(TicketQueueConsumer.class);

    public void processTickets(String message){
        logger.info("Received message "+message);
    }
}
Just by adding two lines in applicationContext.xml, this simple POJO will be able to process the messages asynchronously. That is the beauty of Spring framework :)
   
        
    
web.xml

  
    org.springframework.web.context.ContextLoaderListener
  
  
    org.springframework.web.context.request.RequestContextListener
  
 
     spring-jms
     org.springframework.web.servlet.DispatcherServlet
     
         contextConfigLocation
         /WEB-INF/applicationContext.xml
     
 
 
     spring-jms
     /*
 

pom.xml

  4.0.0
  war
  spring-hornetq
  spring-hornetq
  spring-hornetq
  1.0-SNAPSHOT
  
        
            jboss
            http://repository.jboss.org/maven2
        
  
  
    
      
        org.mortbay.jetty
        maven-jetty-plugin
        6.1.7
        
          
            
              8888
              30000
            
          
          ${project.build.directory}/${pom.artifactId}-${pom.version}
          /
        
      
    
      spring-hornetq
  
  
      
          org.springframework
          spring-core
          3.2.0.RELEASE
      
      
          org.springframework
          spring-jms
          3.2.0.RELEASE
      
      
          org.springframework
          spring-webmvc
          3.2.0.RELEASE
      
      
          javax.servlet
          servlet-api
          2.5
          provided
      
      
          org.springframework
          spring-webmvc
          3.2.0.RELEASE
      
      
          org.hornetq
          hornetq-core-client
          2.3.1.Final
          provided
      
      
          org.hornetq
          hornetq-jms-client
          2.3.1.Final
          provided
      
      
          log4j
          log4j
          1.2.16
          provided
      
  

Happy learning!!!!
If you have any questions please do not hesitate to ask it in comments section. I will be very happy to answer them.
Dear Readers, kindly like this post on facebook or follow me on Google+

Sunday, November 10, 2013

How to debug your applications built by custom ant builds in Intelij Idea

Sometimes things which looks very minor end up taking more time than expected. My transition to Intelij idea from eclipse was pretty smooth with an exception to debugging. In the good old days I was using tomcat as server and eclipse as IDE. Just with a tomcat plugin for eclipse I was able to debug my code. 
Expecting the same and reluctant to use the ant auto generated by intelij idea I wrote my own ant build and wrote some code.After the sweet message "build successful", I deployed it on jboss. Tried to debug the code by placing a break point which to my surprise never reached. After many long hours of experimenting I added debug attribute and turned it on in javac ant task and bingo!!! debug point reached. Hope this saves your time!!!
Happy debugging!!! :)
 

Sunday, September 8, 2013

SHA-256 in JAVA


Note: For mobile users, kindly switch to web version on your mobile.
Security is a very basic requirement which every developer has to keep in mind while designing or developing an application. I would like to take this opportunity to quote a line from the one of the book I read "Every system can be broken, given enough time and money. Let me say that again, every system can be broken". This very quote itself inspired me to blog a series of tutorials regarding security, cryptography and what else is the best place to start other than SHA-256. In the near future I will try to blog more tutorials on digital signatures, how to verify digital signatures, digital certificates based authentication, Keys .....
SHA-2
For a given input SHA-256 will generate a hash value through which the input can be validated and guaranteed that its contents are not tampered. Sender can generate a hash value and share it with the receiver through which receiver can validate the file. If the contents of the file is changed the hash value will also change.(This is what we basically see on many download sites). Below is an example using Message Digest.

SHA256Example.java
package itsvenkis.blogspot.in;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class SHA256Example {

 public static void main(String args[]) {
  FileInputStream fis = null;
  try {
   File file = new File("files.txt");
   if (!file.exists() || file.length() == 0) {
    throw new RuntimeException("Bad input................");
   }
   fis = new FileInputStream(file);
   byte[] fileBytes = new byte[(int) file.length()];
   MessageDigest md = MessageDigest.getInstance("sha-256");
   int length;
   while ((length = fis.read(fileBytes)) != -1) {
    md.update(fileBytes, 0, length);
   }
   byte[] raw = md.digest();
   StringBuilder sb = new StringBuilder();
   for (int i = 0; i < raw.length; i++) {
    byteToHex(raw[i],sb);
   }
   System.out.println("hash value in HEX " + sb.toString());
  } catch (NoSuchAlgorithmException | IOException e) {
   e.printStackTrace();
  } finally {
   if (fis != null) {
    try {
     fis.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
  }
 }

 private static StringBuilder byteToHex(byte b, StringBuilder sb) {
  String hexVal = Integer.toHexString((b & 0xff));
  if (hexVal.length() == 1) {
   return sb.append("0").append(hexVal);
  }
  return sb.append(hexVal);
 }

}

files.txt
itsvenkis blogspot

Output:
cc439a348e5f91e483c9c6c3620ec5b38ee18ce78ff82ccce07aba4493519f70
Dear Readers, kindly like the page on facebook or follow me on Google+.

Friday, September 6, 2013

JMS REST tutorial - HORNETQ REST Interface tutorial


Introduction
HORNETQ is the defualt messaging system provided by JBOSS Application Server. In one of my previous tutorial I covered how to configure, produce and consume Messages through JMS API using HORNETQ as provider. You can find the tutorial @ HERE.
NOTE: This tutorial uses queue named 'restInterfaceQueue'. To know how to create this queue please take a look into the above tutorial.
This tutorial will focus on creating and consuming messages from HORNETQ using REST API.
Why would one ever need to produce and consume messages through REST?
Well!!! I would say to support CROSS LANGUAGE CLIENTS.... and also to provide web based API for messaging. With these capabilities one no longer needs producer and consumer to be through JMS API. So anyone who understands HTTP can produce and consume messages. This one big advantage of REST interface. HORNETQ provides a very good REST interface. Some of the features of REST interface provided by HORNETQ are given below
  • Avoid posting of duplicate messages
  • Mix and match JMS and REST producers and consumers
  • Acknowledgement and auto acknowledgement 

Technologies Used
  • JAVA 
  • J2EE
  • RESTEasy
  • HORNETQ 
  • HORNETQ REST Interface
  • Maven  

Coplete list of features and more information about REST interface and HORNETQ can be found @here. Lets get started!!!! 
Boot strapping HORNETQ with REST
To use HORNETQ REST interface in our application we first need to bootstrap it. This can be done by adding the below listener in web.xml

  org.hornetq.rest.integration.RestMessagingBootstrapListener
 

REST Interface Configuration
We should add some configuration information for REST interface. This can be done in an xml file under WEB-INF/classes. The name of the file should be mentioned in web.xml using rest.messaging.config.file context param

hornetq-rest.xml

   0
   false
   true
   
   true
   topic-push-store
   queue-push-store
   10
   1
   300
   0
The entries in above XML file are explained below
Server-in-vm-id : This is to differentiate different HORNETQ servers running in
same VM. We can default it to zero
Use-link-headers: To tell HORNETQ how to publish the links. By default it publishes
using cutoms headers. This tutorial uses the default behaviour so we can mark it as
false
default-durable-send: Used to identify if the posted message needs to persisted in
DB.We will mark it as false. This default behaviour can be overriddden by sending
durable custom header as true
dups-ok Should duplicate messages be allowed?
client-window-size Used to identify buffering capabilities. By specifying it as zero we are saying we don't want any buffering to happen for delivery of messages.
Now lets take a look at our complete web.xml


 
  rest.messaging.config.file
  hornetq-rest.xml
 

 
  resteasy.resources
  itsvenkis.blogspot.in.rest.services.OrderSrvc
 

 
  resteasy.servlet.mapping.prefix
  /resteasy/hornetq
 

 
  org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
 

 
  org.hornetq.rest.integration.RestMessagingBootstrapListener
 

 
  resteasy
  
   org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
  
 

 
  resteasy
  /resteasy/hornetq/*
 

 
 
    BASIC
 
 
 
  
   Rest-Messaging
   /resteasy/hornetq/queues/*
   GET
   POST
   PUT
   HEAD
   DELETE
  
  
   admin
  
 


We will reuse the modified OrderSrvc.java class here. It has single method which will consume XML message and puts it in Queue using JMS API.
package itsvenkis.blogspot.in.rest.services;

import javax.annotation.Resource;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.Session;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.apache.log4j.Logger;

/**
 * @author itsvenkis
 *
 */
@Path("/postOrder")
public class OrderSrvc {
 
 private final Logger log = Logger.getLogger(OrderSrvc.class);
 /*
  * Map a JNDI connection factory name.As this service is going to be in same
  * JAVA VM as JMS use "java:/ConnectionFactory". You can find this entry in JBOSS server
  * standalone-full.xml configuration file. 
  */
 @Resource(mappedName = "java:/ConnectionFactory")
 private ConnectionFactory connectionFactory;
 
 /*
  * Map the queue. Note how the queue name is defined here. This should match the context
  * of JNDI defined which is "java" namespace followed by the entry name as given in
  * standalone-full.xml configuration file.
  */
 @Resource(mappedName = "java:/queue/restInterfaceQueue")
 private Queue orderQueue;
 
 @POST
 @Consumes(MediaType.APPLICATION_XML)
 public Response postOrder(String xmlStr) throws JMSException{
  log.debug("Started processing the order....");
  Connection con = null;
  try{
   //In real world you may want to do this only once
   con = connectionFactory.createConnection();
   Session session = con.createSession(false,
     Session.AUTO_ACKNOWLEDGE);
   MessageProducer producer = session.createProducer(orderQueue);
   log.debug("starting HornetQ-JMS connection");
   con.start();
   log.debug("started HornetQ-JMS connection");
   //HORNETQ REST accepts only HTTP or OBJECTMESSAGE
   ObjectMessage objMsg = session.createObjectMessage();
   objMsg.setStringProperty("http_content$type",
     "application/xml");
   objMsg.setObject(xmlStr);
   producer.send(objMsg);
   log.debug("Sent message HornetQ-JMS to QUEUE");
  }catch(JMSException e){
   log.error("Failed to push order to the queue ", e);
  }finally{
   if(con != null){
    try{
     con.close();
    }catch(JMSException e){
     log.error("Unexpected error while trying to close the connection", e);
    }
   }
  }
  return Response.status(200).entity("Received XML").build();
 }

}

As we are using JEE 6 i.e. CDI in OrderSrvc.java we are required to turn it on by using a simple beans.xml under WEB-INF directory. It can be a empty XML file
beans.xml





pom.xml

 4.0.0
 in.itsvenkis.blogspot
 JMS-REST-EXAMPLES
 0.0.1-SNAPSHOT
 war
 A simple HORNETQ examples to demonstrate REST interface
 
  
  jms-rest-examples
  
   
    org.apache.maven.plugins
    maven-war-plugin
    
     
      
       org.hornetq
      
     
    
   
  
 
 
  
   jboss
   http://repository.jboss.org/maven2
  
 
 
  
   org.jboss.resteasy
   resteasy-jaxrs
   3.0.0.Final
  
  
   org.jboss.resteasy
   resteasy-jaxb-provider
   3.0.0.Final
  
  
   org.jboss.spec.javax.jms
   jboss-jms-api_1.1_spec
   1.0.1.Final
  
  
   log4j
   log4j
   1.2.17
  
  
   org.hornetq.rest
   hornetq-rest
   2.3.5.Final
  
 


project structure
dependencies

Now build and deploy the application. We are now ready to consume and produce messages using HORNETQ REST interface.
DEMO
Start your server after deploying the war file

Now post our first message to the queue named "restInterfaceQueue" using REST WS call in OrderSrvc.java. It uses regular JMS API to post the message to queue. url to post the xml message using restclient firefox plugin 'http://localhost:8080/jms-rest-examples/resteasy/hornetq/postOrder'

XML posted

Mumbai

300

f238
OR908765


The message counter for the queue should be 1 now as shown in admin console of our JBOSS server.
Now let us consume this message using REST interface. First we will do a GET request to 'http://localhost:8080/jms-rest-examples/resteasy/hornetq/queues/jms.queue.restInterfaceQueue'. To understand how this URL is formed lets break it into pieces
  •  http://localhost:8080/jms-rest-examples- your application context path
  • /resteasy/hornetq- As mapped for RESTEasy path in web.xml
  • /queues- All REST interface URLS should have queues followed by the original queue name itself which is jms.queue.restInterfaceQueue
As you may have already guessed HORNETQ will retrun us some bunch of custom headers with the GET request. Custom headers returned are shown below
Notice the msg-pull-consumer header returned. We will use that URL to create a service so that we can pull the message from the queue. To create a service do a empty post to the URL as mentioned by msg-pull-consumer header

Below are the custom headers returned from above request.

Notice the 'msg-consume-next' header value returned.Do a POST request to this URL to consume/pull the message from the queue.
below is the consumed message

This network roundtrip is just done once and to consume next message we need not issue the GET request again and start the cycle. Instead we can use 'msg-consume-next' header returned to consume next message and do the polling.If by any chance you miss the URL you can issue a get again to get url values as headers.
Now let us look at Produce an message using REST interface
Do a get request to 'http://localhost:8080/jms-rest-examples/resteasy/hornetq/postOrder' and use 'msg-create' header value and do a post

Notice the headers returned from the above POST request.'msg-create-next: http://localhost:8080/jms-rest-examples/resteasy/hornetq/queues/jms.queue.restInterfaceQueue/create'. Do a post to the URL returned as mentioned by 'msg-create-next' to create a message in the queue

This will create a new message in the queue.
This brings us to the end of the tutorial which covers how to post message and consume message using REST interface.
I was really excited to see producers and consumers via REST interface in JMS queue. If your application needs to support cross platform messaging I would strongly suggest to use REST interface.
Hope this tutorial helps you to understand REST interface. If you have any questions please do not hesitate to ask it in comments section. I will be very happy to answer them.
Dear Readers, kindly like us on facebook or follow me on Google+

Saturday, August 31, 2013

Exceptions!!!!! Hornetq Exception solved


java.lang.RuntimeException: HornetQException[errorType=NOT_CONNECTED message=HQ119007: Cannot connect to server(s). Tried with all available servers.]
One of the exception I ran into while experimenting with HORNETQ REST INTERFACE. Hope this saves your time!!!!
This is caused because of not mentioning hornetq and netty dependencies in MANIFEST.MF file. Just add "Dependencies: org.hornetq, org.jboss.netty" in MANIFEST.MF in your WAR file or in your pom.xml.

    org.apache.maven.plugins
    maven-war-plugin
    
     
      
       org.hornetq,org.jboss.netty
      
     
    
   
Exception full stack trace
15:05:57,228 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/jms-rest-examples]] (ServerService Thread Pool -- 59) JBWEB000287: Exception sending context initialized event to listener instance of class org.hornetq.rest.integration.RestMessagingBootstrapListener: java.lang.RuntimeException: HornetQException[errorType=NOT_CONNECTED message=HQ119007: Cannot connect to server(s). Tried with all available servers.]
 at org.hornetq.rest.integration.RestMessagingBootstrapListener.contextInitialized(RestMessagingBootstrapListener.java:40) [hornetq-rest-2.3.5.Final.jar:]
 at org.apache.catalina.core.StandardContext.contextListenerStart(StandardContext.java:3339) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
 at org.apache.catalina.core.StandardContext.start(StandardContext.java:3777) [jbossweb-7.2.0.Final-redhat-1.jar:7.2.0.Final-redhat-1]
 at org.jboss.as.web.deployment.WebDeploymentService.doStart(WebDeploymentService.java:156) [jboss-as-web-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]
 at org.jboss.as.web.deployment.WebDeploymentService.access$000(WebDeploymentService.java:60) [jboss-as-web-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]
 at org.jboss.as.web.deployment.WebDeploymentService$1.run(WebDeploymentService.java:93) [jboss-as-web-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]
 at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) [rt.jar:1.7.0_25]
 at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) [rt.jar:1.7.0_25]
 at java.util.concurrent.FutureTask.run(FutureTask.java:166) [rt.jar:1.7.0_25]
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_25]
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_25]
 at java.lang.Thread.run(Thread.java:724) [rt.jar:1.7.0_25]
 at org.jboss.threads.JBossThread.run(JBossThread.java:122)
Caused by: HornetQException[errorType=NOT_CONNECTED message=HQ119007: Cannot connect to server(s). Tried with all available servers.]
 at org.hornetq.core.client.impl.ServerLocatorImpl.createSessionFactory(ServerLocatorImpl.java:863) [hornetq-core-client-2.3.5.Final.jar:]
 at org.hornetq.rest.MessageServiceManager.start(MessageServiceManager.java:157) [hornetq-rest-2.3.5.Final.jar:]
 at org.hornetq.rest.integration.RestMessagingBootstrapListener.contextInitialized(RestMessagingBootstrapListener.java:34) [hornetq-rest-2.3.5.Final.jar:]
 ... 12 more

15:05:57,290 ERROR [org.apache.catalina.core] (ServerService Thread Pool -- 59) JBWEB001103: Error detected during context /jms-rest-examples start, will stop it
15:05:57,311 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 59) MSC000001: Failed to start service jboss.web.deployment.default-host./jms-rest-examples: org.jboss.msc.service.StartException in service jboss.web.deployment.default-host./jms-rest-examples: org.jboss.msc.service.StartException in anonymous service: JBAS018040: Failed to start context
 at org.jboss.as.web.deployment.WebDeploymentService$1.run(WebDeploymentService.java:96)
 at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) [rt.jar:1.7.0_25]
 at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) [rt.jar:1.7.0_25]
 at java.util.concurrent.FutureTask.run(FutureTask.java:166) [rt.jar:1.7.0_25]
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_25]
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_25]
 at java.lang.Thread.run(Thread.java:724) [rt.jar:1.7.0_25]
 at org.jboss.threads.JBossThread.run(JBossThread.java:122) [jboss-threads-2.1.0.Final-redhat-1.jar:2.1.0.Final-redhat-1]
Caused by: org.jboss.msc.service.StartException in anonymous service: JBAS018040: Failed to start context
 at org.jboss.as.web.deployment.WebDeploymentService.doStart(WebDeploymentService.java:161)
 at org.jboss.as.web.deployment.WebDeploymentService.access$000(WebDeploymentService.java:60)
 at org.jboss.as.web.deployment.WebDeploymentService$1.run(WebDeploymentService.java:93)
 ... 7 more

Tuesday, August 27, 2013

Simple HornetQ JMS Tutorial


If you are interested to see the other REST tutorials I already blogged, please find them below
As part of series of REST tutorials, I am blogging this simple HorneQ JMS tutorial. HornetQ is the default meessaging system in JBOSS application server.
A detailed documentation about HornetQ is available @ here.Lets get started with the tutorial
Technologies used
  • HornetQ
  • JBOSS eap 6.1
  • JAVA 7
  • RESTEasy
  • CDI
  • Maven
 Now lets see what configuration we require before we start our coding. Before we start any configuration a basic understanding of JBOSS server is required. JBOSS server directory structure will look this

Different startup configurations are available in JBOSS server. To have the HORNETQ integrated and started with JBOSS AS one should use standalone-full.xml. For example we will start the server using this command
./standalone.sh --server-config=standalone-full.xml.
We will add the queues needed for our tutorial in standalone-full.xml. There are other ways too to declare the queues/topics which is out of scope of this post. I am gonna develop a order processing system which can receive a order which is a XML file and it will put the order in a queue which will be consumed by other consumers. Lets name that queue as "ticketOrderQueue". Here is how we declare in standalone-full.xml
                 
                    
                        
                        
                    
                    
                        
                        
                    
                
To connect to this queues we will use JNDI connection factories. By default JBOSS gives us couple of connection factories like "InvmConnectionFactory" and "RemoteConnectionFactory" which will use netty connector. Code snippet of these factories is below

                        
                            
                        
                        
                            
                        
                    
                    
                        
                            
                        
                        
                            
                        
                    

If our message producer or consumer is in same JAVA VM as HornetQ one should use "java:/ConnectionFactory" and if it is remote client consuming or producing messaging to JMS destinations one should use "RemoteConnectionFactory". Noteworthy about the contexts they use as shown in above snippet. For example, "RemoteConenctionFactory" uses "java:jboss/exported" context. Once this is done, we will define users for JBOSS application server as administrator and for HORNETQ. Use add-user utility to add application users. Note: I am using UBUNTU as my dev env. However for windows it should be the same process with bat files First let us add admin user. Please find the details in below screenshot

Now let us add some application users for HORNETQ. Please find the details below

Now start the server and we will add some security to our HORNETQ. start server

type in and enter the credentials you configured for admin as mentioned above and select JMS destination from left hand menu. You should now be able to see this view with the queues which we defined

To add some security to our HORNETQ lets go to profile view by clicking on profile link on top right side on admin view and select Messaging/destination/view and select security settings and add the role permissions as shown below

This should bring us to end of configuration section. Now lets start coding our producer which is a RESTFUL web service and receives a XML order and pushes it to a queue. OrderSrvc.java
package itsvenkis.blogspot.in.rest.services;

import javax.annotation.Resource;
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.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.apache.log4j.Logger;

/**
 * @author itsvenkis
 *
 */
@Path("/postOrder")
public class OrderSrvc {
 
 private final Logger log = Logger.getLogger(OrderSrvc.class);
 /*
  * Map a JNDI connection factory name.As this service is going to be in same
  * JAVA VM as JMS use "java:/ConnectionFactory". You can find this entry in JBOSS server
  * standalone-full.xml configuration file. 
  */
 @Resource(mappedName = "java:/ConnectionFactory")
 private ConnectionFactory connectionFactory;
 
 /*
  * Map the queue. Note how the queue name is defined here. This should match the context
  * of JNDI defined which is "java" namespace followed by the entry name as given in
  * standalone-full.xml configuration file.
  */
 @Resource(mappedName = "java:/queue/ticketOrderQueue")
 private Queue orderQueue;
 
 @POST
 @Consumes(MediaType.APPLICATION_XML)
 public Response postOrder(String xmlStr) throws JMSException{
  log.debug("Started processing the order....");
  Connection con = null;
  try{
   //In real world you may want to do this only once
   con = connectionFactory.createConnection();
   Session session = con.createSession(false,
     Session.AUTO_ACKNOWLEDGE);
   MessageProducer producer = session.createProducer(orderQueue);
   log.debug("starting HornetQ-JMS connection");
   con.start();
   log.debug("started HornetQ-JMS connection");
   TextMessage txtMsg = session.createTextMessage();
   txtMsg.setText(xmlStr);
   producer.send(txtMsg);
   log.debug("Sent message HornetQ-JMS to QUEUE");
  }catch(JMSException e){
   log.error("Failed to push order to the queue ", e);
  }finally{
   if(con != null){
    try{
     con.close();
    }catch(JMSException e){
     log.error("Unexpected error while trying to close the connection", e);
    }
   }
  }
  return Response.status(200).entity("Received XML").build();
 }

}

In the above web service I used @Resource annotation which is nothing but through CDI. Inorder to make CDI work one should have a beans.xml defined under WEB-INF folder. This xml will tell JBOSS to enable CDI.Noteworthy that this xml can be empty. I will add tutorials specific to CDI in the near future. For now,please find the xml below





web.xml

 
  resteasy.resources
  itsvenkis.blogspot.in.rest.services.OrderSrvc
 
 
  resteasy.servlet.mapping.prefix
  /resteasy
 
 
  
   org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
 
 
  resteasy
  
   org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
 
 
  resteasy
  /resteasy/*
 


pom.xml

  4.0.0
  in.itsvenkis.blogspot
  JMS-flight-booking
  0.0.1-SNAPSHOT
  war
  
  jms-flight-booking
  
  Simple application to understand RESTEasy,Hornet Q
  
   
      jboss
      http://repository.jboss.org/maven2
   
   
   
   
    org.jboss.resteasy
    resteasy-jaxrs
    3.0.0.Final
   
   
 org.jboss.resteasy
 resteasy-jaxb-provider
 3.0.0.Final
 
 
 org.jboss.spec.javax.jms
 jboss-jms-api_1.1_spec
 1.0.1.Final
 
 
 log4j
 log4j
 1.2.17
 
  


Now build,deploy and start your server. We will restful mozilla plugin to post XML file to our URL

To check if the message has reached our "ticketOrderQueue" go to admin view in the JBOSS server and goto JMS view. You should be able to see messages in queue count as one

Now lets code a simple consumer class which will have a main method
package itsvenkis.blogspot.in.example.consumer;

import java.util.Properties;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;

public class JMSConsumerExample {
 /*
  * for a remote client use RemoteConnectionFactory JNDI which will be defined in standalone-full.xml
  * configuration file
  */
 private static final String DEFAULT_CONNECTION_FACTORY = "jms/RemoteConnectionFactory";
 //Queue name as mentioned in standalone-full.xml under 
 private static final String DEFAULT_DESTINATION = "jms/queue/ticketOrderQueue";
 private static final String DEFAULT_USERNAME = "jmsadmin";
 private static final String DEFAULT_PASSWORD = "*****";
 private static final String INITIAL_CONTEXT_FACTORY = "org.jboss.naming.remote.client.InitialContextFactory";
 private static final String PROVIDER_URL = "remote://localhost:4447";

 public static void main(String[] args) throws Exception {
  ConnectionFactory connectionFactory = null;
  Connection connection = null;
  Session session = null;
  MessageConsumer consumer = null;
  Destination destination = null;
  TextMessage message = null;
  Context context = null;
  try {
   final Properties env = new Properties();
   env.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
   env.put(Context.PROVIDER_URL,
     System.getProperty(Context.PROVIDER_URL, PROVIDER_URL));
   env.put(Context.SECURITY_PRINCIPAL,
     System.getProperty("username", DEFAULT_USERNAME));
   env.put(Context.SECURITY_CREDENTIALS,
     System.getProperty("password", DEFAULT_PASSWORD));
   context = new InitialContext(env);
   String connectionFactoryString = System.getProperty(
     "connection.factory", DEFAULT_CONNECTION_FACTORY);
   connectionFactory = (ConnectionFactory) context
     .lookup(connectionFactoryString);
   String destinationString = System.getProperty("destination",
     DEFAULT_DESTINATION);
   destination = (Destination) context.lookup(destinationString);
   connection = connectionFactory.createConnection(
     System.getProperty("username", DEFAULT_USERNAME),
     System.getProperty("password", DEFAULT_PASSWORD));
   session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
   consumer = session.createConsumer(destination);
   connection.start();
   message = (TextMessage) consumer.receive(10000);
   System.out.println("Received message " + message.getText());
  } catch (Exception e) {
   System.out.println(e.getMessage());
   throw e;
  } finally {
   if (context != null) {
    context.close();
   }
   if (connection != null) {
    connection.close();
   }
  }
 }
}

Run the application and you should be able to see this output now

Project directory structure

Project dependencies
This brings us to the end of this tutorial!!!!
Dear Readers, kindly like us on facebook