Showing posts with label jetty. Show all posts
Showing posts with label jetty. Show all posts

Enabling Request and Response logging in Jersey

I have been using Jersey as JAX-RS reference implementation for building REST services for last few days. And i wanted to enable logging so that it makes debugging easier. It seems that Jersey allows us to enable Request and Response logging and once you enable that it starts printing request and response info. In order to use that all you have to do is change web.xml to add LoggingFilter on both request and response like this

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>

    <init-param>
         <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
         <param-value>com.sun.jersey.api.container.filter.LoggingFilter</param-value>
     </init-param>
     <init-param>
         <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
         <param-value>com.sun.jersey.api.container.filter.LoggingFilter</param-value>
     </init-param>
   
 <init-param>
      <param-name>javax.ws.rs.Application</param-name>
      <param-value>com.webspherenotes.rest.ContactApplication</param-value>
    </init-param>
  
  </servlet>
  <servlet-mapping>
    <servlet-name>Jersey Web Application</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>

</web-app>
The com.sun.jersey.api.container.filter.LoggingFilter can be used to enable loggin on either request or response or both as i am doing in this case. Now if i hit a REST service by making GET call to http://localhost:9000/ManageContact/rest/contact/5 then the service returns JSON reso If you look into the generated log you can see both the request and response being printed like this

Securing REST service using annotations

In the Security REST service using web.xml entry i talked about how you can protect a REST service by adding security-constraint element in the web.xml. But JAXRS provides annotations that would give you more granular control over the REST services. I wanted to try that feature so i changed the same ManageContactApp to use the javax.annotation.security annotations. You can download the sample application from here When the user tries to insert a new record he will get prompted for basic authentication like this I followed these steps to build the sample application
  1. First i did download the basic ManageContactApp.zip that provides REST interface and i tested it to make sure that it works
  2. Next i used the instructions in Securing web application deployed in Jetty to make changes in Maven build file(pom.xml) to enable loginService in Jetty
    
    <build>
      <finalName>JettySecurity</finalName>
      <plugins>
        <plugin>
          <groupId>org.mortbay.jetty</groupId>
          <artifactId>jetty-maven-plugin</artifactId>
          <version>7.4.5.v20110725</version>
          <configuration>
            <scanIntervalSeconds>10</scanIntervalSeconds>
            <webAppConfig>
              <contextPath>/JettySecurity</contextPath>
            </webAppConfig>
            <loginServices>
              <loginService implementation="org.eclipse.jetty.security.HashLoginService">
                <name>Default</name>
                <config>${basedir}/src/main/resources/realm.properties</config>
              </loginService>
            </loginServices> 
            <connectors>
              <connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
                <port>9000</port>
                <maxIdleTime>60000</maxIdleTime>
              </connector>
            </connectors>
          </configuration>
        </plugin>
      </plugins>
    </build>
    
  3. Next create realm.properties file in ${basedir}/src/main/resources directory which looks like this
    
    guest:guest
    admin:admin,ADMIN
    
    This file has only 2 users first is guest and second is admin the admin user has ADMIN role.
  4. Next change the web.xml file to declare the ADMIN role and define BASIC authentication scheme for the web application like this.
    
    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
      <servlet>
        <servlet-name>Jersey Web Application</servlet-name>
        <servlet-class>
    	com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
          <param-name>javax.ws.rs.Application</param-name>
          <param-value>com.webspherenotes.rest.ContactApplication</param-value>
        </init-param>
    
        <init-param>
          <param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
          <param-value>
    	  com.sun.jersey.api.container.filter.RolesAllowedResourceFilterFactory</param-value>
        </init-param>
       
     <load-on-startup>1</load-on-startup>
      </servlet>
      <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/rest/*</url-pattern>
      </servlet-mapping>
    
    
      <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>Default</realm-name>
      </login-config>
    
      <security-role>
        <role-name>ADMIN</role-name>
      </security-role>
    </web-app>
    
    By default the Jersey implementation does not look for security annotations in your REST service, in order for that to work you must set value of com.sun.jersey.spi.container.ResourceFilters init parameter to com.sun.jersey.api.container.filter.RolesAllowedResourceFilterFactory this filter takes care of parsing and understanding PermitAll, RolesAllowed and DenyAll annotations
  5. The last step is to change the ContactService.java to use the security related annotations at individual class and method level
    
    package com.webspherenotes.rest;
    
    import java.util.List;
    
    import javax.annotation.security.PermitAll;
    import javax.annotation.security.RolesAllowed;
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Query;
    import javax.ws.rs.Consumes;
    import javax.ws.rs.DELETE;
    import javax.ws.rs.FormParam;
    import javax.ws.rs.GET;
    import javax.ws.rs.POST;
    import javax.ws.rs.PUT;
    import javax.ws.rs.Path;
    import javax.ws.rs.PathParam;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    @Path("/contact")
    
    public class ContactService {
    
      Logger logger = LoggerFactory.getLogger(ContactService.class);
      
      EntityManagerFactory entityManagerFactory;
      public ContactService(EntityManagerFactory entityManagerFactory){
        this.entityManagerFactory=entityManagerFactory;
      }
    
      @GET
      @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
      public List getContactList() {
        logger.debug("Entering ContactService.getContactList()");
    
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        Query q = entityManager.createQuery("SELECT x from Contact x");
        logger.debug("Exiting ContactService.getContactList()");
    
        return (List) q.getResultList();
      }
    
      @GET
      @Path("/{contactId}")
      @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
      public Contact getContact(@PathParam("contactId") int contactId) {
        logger.debug("Entering ContactService.getContact() contactId" + contactId);
    
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        Contact contact = entityManager.find(Contact.class, contactId);
        logger.debug("Exiting ContactService.getContact()" );
    
        return contact;
      }
      
      @POST
      @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
      @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
      @RolesAllowed("ADMIN")
      public Contact insertContact(@FormParam("contactId") int contactId,
          @FormParam("firstName") String firstName,
          @FormParam("lastName") String lastName,
          @FormParam("email") String email) {
        logger.debug("Entering ContactService.insertContact()");
    
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        Contact contact = new Contact();
        contact.setContactId(contactId);
        contact.setFirstName(firstName);
        contact.setLastName(lastName);
        contact.setEmail(email);
        try{
        entityManager.getTransaction().begin();
        
        entityManager.persist(contact);
        entityManager.getTransaction().commit();
        }catch(Throwable t){
          if(entityManager.getTransaction().isActive())
            entityManager.getTransaction().rollback();
          contact = null;
        }finally{
          entityManager.close();
        }
        logger.debug("Exiting ContactService.insertContact()");
        return contact;
      }
    
    
      @PUT
      @Path("/{contactId}")
      @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
      @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
      @RolesAllowed("ADMIN")
      public Contact updateContact(@PathParam("contactId") int contactId,
          @FormParam("firstName") String firstName,
          @FormParam("lastName") String lastName,
          @FormParam("email") String email) {
        logger.debug("Entering ContactService.update() contactId" + contactId);
    
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        Contact contact = new Contact();
        contact.setContactId(contactId);
        contact.setFirstName(firstName);
        contact.setLastName(lastName);
        contact.setEmail(email);
        try{
        entityManager.getTransaction().begin();
        entityManager.merge(contact);
        entityManager.getTransaction().commit();
        }catch(Throwable t){
          if(entityManager.getTransaction().isActive())
            entityManager.getTransaction().rollback();
          contact = null;
        }finally{
          entityManager.close();
        }
        logger.debug("Exiting ContactService.updateContact()");
    
        return contact;
      }
    
      @DELETE
      @Path("/{contactId}")
      @RolesAllowed("ADMIN")
      public void deleteContact(@PathParam("contactId") int contactId) {
        logger.debug("Entering ContactService.deleteContact() contactId " + contactId);
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        try{
          entityManager.getTransaction().begin();
          Contact contact = entityManager.find(Contact.class, contactId);
          logger.debug("remove contact " + contact);
          entityManager.remove(contact);
          logger.debug("After removing " + contact);
          entityManager.getTransaction().commit();
          }catch(Throwable t){
            if(entityManager.getTransaction().isActive())
              entityManager.getTransaction().rollback();
    
          }finally{
            entityManager.close();
          }
        logger.debug("Exiting ContactService.deleteContact()");
      }
    
    }
    
    By default all the methods are accessible to user. But i did add @RolesAllowed("ADMIN") to insertContact(), updateContact() and deleteContact() method to say that only users who have admin rights can access these methods.

Security REST service using web.xml

In the Using JPA in REST web application deployed in Jetty entry i talked about how to create a REST service which uses JPA to interact with database. This service allows you to list, insert, update and delete records from CONTACT table. When you create a service that allows you to update your back end you might want to protect it so that only authorized user can update the database. I wanted to figure out how to protect the service so that every user can get list of contacts but only ADMIN user is able to modify the contacts by inserting, updating and deleting them. YOu can download the sample application that i developed from here When the user tries to insert a new record he will get prompted for basic authentication like this I followed these steps to build the sample application
  1. First i did download the basic ManageContactApp.zip that provides REST interface and i tested it to make sure that it works
  2. Next i used the instructions in Securing web application deployed in Jetty to make changes in Maven build file(pom.xml) to enable loginService in Jetty
    
    <build>
      <finalName>JettySecurity</finalName>
      <plugins>
        <plugin>
          <groupId>org.mortbay.jetty</groupId>
          <artifactId>jetty-maven-plugin</artifactId>
          <version>7.4.5.v20110725</version>
          <configuration>
            <scanIntervalSeconds>10</scanIntervalSeconds>
            <webAppConfig>
              <contextPath>/JettySecurity</contextPath>
            </webAppConfig>
            <loginServices>
              <loginService implementation="org.eclipse.jetty.security.HashLoginService">
                <name>Default</name>
                <config>${basedir}/src/main/resources/realm.properties</config>
              </loginService>
            </loginServices> 
            <connectors>
              <connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
                <port>9000</port>
                <maxIdleTime>60000</maxIdleTime>
              </connector>
            </connectors>
          </configuration>
        </plugin>
      </plugins>
    </build>
    
  3. Next create realm.properties file in ${basedir}/src/main/resources directory which looks like this
    
    guest:guest
    admin:admin,ADMIN
    
    This file has only 2 users first is guest and second is admin the admin user has ADMIN role.
  4. The next step is to make changes in web.xml to protect the appropriate HTTP method calls in web.xml like this
    
    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
      <servlet>
        <servlet-name>Jersey Web Application</servlet-name>
        <servlet-class>
    	com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param> 
              <param-name>javax.ws.rs.Application</param-name> 
              <param-value>
    		  com.webspherenotes.rest.ContactApplication</param-value> 
        </init-param>
        <load-on-startup>1</load-on-startup>
      </servlet>
      <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/rest/*</url-pattern>
      </servlet-mapping>
    
    
      <security-constraint>
        <web-resource-collection>
          <web-resource-name>Create Contact</web-resource-name>
          <url-pattern>/rest/*</url-pattern>
          <http-method>POST</http-method>
          <http-method>PUT</http-method>
          <http-method>DELETE</http-method>
        </web-resource-collection>
        <auth-constraint>
          <role-name>ADMIN</role-name>
        </auth-constraint>
      </security-constraint>
    
      <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>Default</realm-name>
      </login-config>
    
      <security-role>
        <role-name>ADMIN</role-name>
      </security-role>
    
    </web-app>
    
    The most important change in web.xml is defining the security constraints for the /rest URL, which is the base URL for the REST service. The security constraint says that only allow those users who have ADMIN role access to POST, PUT, DELETE HTTP methods on this URL. The login-config element says that use Basic authentication
Now run the web application by executing mvn jetty:run and you will notice that you can get list of contacts but when you try to either insert a new contact or delete existing contact then you will get prompted for userid and password

Securing web application deployed in Jetty

I wanted to figure out how to secure web application that is deployed in Jetty. Basic idea was i did create a UserServlet when user tries to access it he should be prompted for basic authentication and once user logs in check if he has admin role if yes then display "You have reached secure call" message, You can download the sample application from here This screen shot represents when user gets basic authentication prompt This is screen shot of screen that is displayed to the user after successful login I followed these steps to create the secured web application
  1. First i did create a UserServlet.java like this
    
    package com.webspherenotes.rest;
    import java.io.IOException;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class UserServlet extends HttpServlet{
    
      @Override
      protected void doGet(HttpServletRequest req, HttpServletResponse resp)
          throws ServletException, IOException {
        resp.setContentType("text/html");
        resp.getWriter().println("You have reached secure call");
      }
    
    }
    
    
    This servlet has only doGet() method and when it gets control it writes You have reached secure call message in the output
  2. Next i changed the web.xml to protect the UserServlet so that it looks like this
    
    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
      <servlet>
        <servlet-name>User</servlet-name>
        <servlet-class>com.webspherenotes.rest.UserServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>User</servlet-name>
        <url-pattern>/user</url-pattern>
      </servlet-mapping>
    
      <security-constraint>
        <web-resource-collection>
          <web-resource-name>user</web-resource-name>
          <url-pattern>/user</url-pattern>
          <http-method>GET</http-method>
        </web-resource-collection>
        <auth-constraint>
          <role-name>ADMIN</role-name>
        </auth-constraint>
      </security-constraint>
    
      <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>Default</realm-name>
      </login-config>
    
      <security-role>
        <role-name>ADMIN</role-name>
      </security-role>
    </web-app>
    
    The security-constraint element says that protect GET calls to /user url and allow only those users who have ADMIN user right to access the servlet. The login-config element defines Default as realm name
  3. Next change the maven build file to configure maven-compiler-plugin so that it uses login service
    
    <build>
      <finalName>JettySecurity</finalName>
      <plugins>
        <plugin>
          <groupId>org.mortbay.jetty</groupId>
          <artifactId>jetty-maven-plugin</artifactId>
          <version>7.4.5.v20110725</version>
          <configuration>
            <scanIntervalSeconds>10</scanIntervalSeconds>
            <webAppConfig>
              <contextPath>/JettySecurity</contextPath>
            </webAppConfig>
            <loginServices>
              <loginService implementation="org.eclipse.jetty.security.HashLoginService">
                <name>Default</name>
                <config>${basedir}/src/main/resources/realm.properties</config>
              </loginService>
            </loginServices> 
            <connectors>
              <connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
                <port>9000</port>
                <maxIdleTime>60000</maxIdleTime>
              </connector>
            </connectors>
          </configuration>
        </plugin>
      </plugins>
    </build>
    
    The loginService element asks Jetty to use list of users and passwords from ${basedir}/src/main/resources/realm.properties file to authenticate users
  4. Next create realm.properties file which looks like this
    
    guest:guest
    admin:admin,ADMIN
    
    This file has only 2 users first is guest and second is admin the admin user has ADMIN role.
Now if you deploy the application by executing mvn jetty:run and then try accessing http://localhost:9000/JettySecurity/user URL you will get prompted for login. If you login as admin, admin then you should be able to access the UserServlet. But if you login as guest then you should see this error page

Using JPA in REST web application deployed in Jetty

I wanted to figure out how to use Hibernate JPA in a web application deployed in Jetty server, so i built this sample Contact REST service that uses JPA to perform CRUD operations on the CONTACT table and expose those operations using REST, you can download it from here I followed these steps to build the REST service.
  1. First i did create a Contact.java class which is a Entity class representing CONTACT table
    
    package com.webspherenotes.rest;
    
    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.xml.bind.annotation.XmlRootElement;
    
    @Entity
    @XmlRootElement
    public class Contact {
     @Id
     private int contactId;
    
     private String firstName;
     private String lastName;
     private String email;
     
     public int getContactId() {
      return contactId;
     }
     public void setContactId(int contactId) {
      this.contactId = contactId;
     }
     public String getFirstName() {
      return firstName;
     }
     public void setFirstName(String firstName) {
      this.firstName = firstName;
     }
     public String getLastName() {
      return lastName;
     }
     public void setLastName(String lastName) {
      this.lastName = lastName;
     }
     public String getEmail() {
      return email;
     }
     public void setEmail(String email) {
      this.email = email;
     }
     
     @Override
     public String toString() {
      return "Contact [contactId=" + contactId + ", firstName=" + firstName
        + ", lastName=" + lastName + ", email=" + email + "]";
     }
    }
    
    The contactId field represents the primary key for contact table. The Contact class has Entity annotation that maps it to table in database.
  2. Then i did create peristence.xml file which acts as deployment descriptor for the JPA in the META-INF folder of the application like this
    
    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="2.0"
     xmlns="http://java.sun.com/xml/ns/persistence" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
     http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
     <persistence-unit name="MyJPAJAXRS">
      <class>com.webspherenotes.rest.Contact</class>
      <properties>
       <property name="javax.persistence.jdbc.driver" 
       value="org.apache.derby.jdbc.ClientDriver" />
       <property name="javax.persistence.jdbc.url" 
       value="jdbc:derby://localhost:1527/C:/data/contact;create=true" />
       <property name="javax.persistence.jdbc.user" value="dbadmin" />
       <property name="javax.persistence.jdbc.password" value="dbadmin" />
      </properties>
     </persistence-unit>
    </persistence>
    
    The persistence.xml file is using JDBC driver properties for connecting to Apache Derby database.
  3. Create ContactApplication.java class which be the Application class for this REST application
    
    package com.webspherenotes.rest;
    javascript:void(0);
    import java.util.HashSet;
    import java.util.Set;
    
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Persistence;
    import javax.ws.rs.ApplicationPath;
    import javax.ws.rs.core.Application;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    @ApplicationPath("rest")
    public class ContactApplication extends Application{
      Logger logger = LoggerFactory.getLogger(ContactApplication.class);
    
      @Override
      public Set<Object> getSingletons() {
        logger.debug("Entering ContactApplication.getSingletons()");
        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("MyJPAJAXRS");
        ContactService contactService = new ContactService(entityManagerFactory);
        Set<Object> singletons = new HashSet<Object>();
        singletons.add(contactService);
        logger.debug("Exiting ContactApplication.getSingletons()");
        return singletons;
      }
    
    }
    
    The ContactApplication class overrides getSingletons() method so that it can create single instance of ContactService, which will be responsible for handling all the requests for ContactService. Since Jersey in not JEE 6 container i am responsible for creating object of EntityManagerFactory. After creating object of EntityManagerFactory i am injecting it into the ContactService class.
  4. The last step is to create ContactService.java, which exposes the REST operations
    
    package com.webspherenotes.rest;
    
    import java.util.List;
    
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Query;
    import javax.ws.rs.Consumes;
    import javax.ws.rs.DELETE;
    import javax.ws.rs.FormParam;
    import javax.ws.rs.GET;
    import javax.ws.rs.POST;
    import javax.ws.rs.PUT;
    import javax.ws.rs.Path;
    import javax.ws.rs.PathParam;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    @Path("/contact")
    public class ContactService {
    
      Logger logger = LoggerFactory.getLogger(ContactService.class);
      
      EntityManagerFactory entityManagerFactory;
      public ContactService(EntityManagerFactory entityManagerFactory){
        this.entityManagerFactory=entityManagerFactory;
      }
    
      @GET
      @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
      public List getContactList() {
        logger.debug("Entering ContactService.getContactList()");
    
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        Query q = entityManager.createQuery("SELECT x from Contact x");
        logger.debug("Exiting ContactService.getContactList()");
    
        return (List) q.getResultList();
      }
    
      @GET
      @Path("/{contactId}")
      @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
      public Contact getContact(@PathParam("contactId") int contactId) {
        logger.debug("Entering ContactService.getContact() contactId" + contactId);
    
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        Contact contact = entityManager.find(Contact.class, contactId);
        logger.debug("Exiting ContactService.getContact()" );
    
        return contact;
      }
      
      @POST
      @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
      @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
      public Contact insertContact(@FormParam("contactId") int contactId,
          @FormParam("firstName") String firstName,
          @FormParam("lastName") String lastName,
          @FormParam("email") String email) {
        logger.debug("Entering ContactService.insertContact()");
    
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        Contact contact = new Contact();
        contact.setContactId(contactId);
        contact.setFirstName(firstName);
        contact.setLastName(lastName);
        contact.setEmail(email);
        try{
        entityManager.getTransaction().begin();
        
        entityManager.persist(contact);
        entityManager.getTransaction().commit();
        }catch(Throwable t){
          if(entityManager.getTransaction().isActive())
            entityManager.getTransaction().rollback();
          contact = null;
        }finally{
          entityManager.close();
        }
        logger.debug("Exiting ContactService.insertContact()");
        return contact;
      }
    
    
      @PUT
      @Path("/{contactId}")
      @Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
      @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
      public Contact updateContact(@PathParam("contactId") int contactId,
          @FormParam("firstName") String firstName,
          @FormParam("lastName") String lastName,
          @FormParam("email") String email) {
        logger.debug("Entering ContactService.update() contactId" + contactId);
    
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        Contact contact = new Contact();
        contact.setContactId(contactId);
        contact.setFirstName(firstName);
        contact.setLastName(lastName);
        contact.setEmail(email);
        try{
        entityManager.getTransaction().begin();
        entityManager.merge(contact);
        entityManager.getTransaction().commit();
        }catch(Throwable t){
          if(entityManager.getTransaction().isActive())
            entityManager.getTransaction().rollback();
          contact = null;
        }finally{
          entityManager.close();
        }
        logger.debug("Exiting ContactService.updateContact()");
    
        return contact;
      }
    
      @DELETE
      @Path("/{contactId}")
    
      public void deleteContact(@PathParam("contactId") int contactId) {
        logger.debug("Entering ContactService.deleteContact() contactId " + contactId);
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        try{
          entityManager.getTransaction().begin();
          Contact contact = entityManager.find(Contact.class, contactId);
          logger.debug("remove contact " + contact);
          entityManager.remove(contact);
          logger.debug("After removing " + contact);
          entityManager.getTransaction().commit();
          }catch(Throwable t){
            if(entityManager.getTransaction().isActive())
              entityManager.getTransaction().rollback();
    
          }finally{
            entityManager.close();
          }
        logger.debug("Exiting ContactService.deleteContact()");
      }
    
    }
    
    The ContactService class exposes CRUD operations on the CONTACT table using REST

Enabling request Log in Embedded Jetty

You can enable NCSA logging in Jetty so that it starts logging every request that enters Jetty with request details like this. It can be very useful for debugging sometimes. 127.0.0.1 - - [11/Apr/2012:15:44:19 +0000] "GET /ManageContact/rest/contact HTTP/1.1" 200 471 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.152 Safari/535.19" 127.0.0.1 - - [11/Apr/2012:15:44:21 +0000] "GET /ManageContact/rest/contact HTTP/1.1" 200 471 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.152 Safari/535.19" 127.0.0.1 - - [11/Apr/2012:15:44:26 +0000] "GET /ManageContact/rest/contact HTTP/1.1" 200 276 "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.152 Safari/535.19" You can use following plugin configuration to enable the NCSA logging

<plugin>
  <groupId>org.mortbay.jetty</groupId>
  <artifactId>jetty-maven-plugin</artifactId>
  <version>7.4.5.v20110725</version>
  <configuration>
    <scanIntervalSeconds>10</scanIntervalSeconds>
    <webAppConfig>
      <contextPath>/ManageContact</contextPath>
    </webAppConfig> <!-- <loginServices> <loginService implementation="org.eclipse.jetty.security.HashLoginService"> 
      <name>Test Realm</name> <config>${basedir}/src/etc/realm.properties</config> 
      </loginService> </loginServices> -->
    <connectors>
      <connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
        <port>9000</port>
        <maxIdleTime>60000</maxIdleTime>
      </connector>
    </connectors>
 
    <requestLog implementation="org.eclipse.jetty.server.NCSARequestLog">
      <filename>target/yyyy_mm_dd.request.log</filename>
      <retainDays>90</retainDays>
      <append>true</append>
      <extended>true</extended>
      <logTimeZone>GMT</logTimeZone>
    </requestLog>
 
  </configuration>
</plugin>
After this start the Jetty server and when you hit the service you will notice that a .log file gets created in the target directory with one entry for every request.

Change the default port in Jetty

The Using Embedded Jetty server entry talks about how to embed a Jetty server using Maven in web application. By default the embedded Jetty server starts at port 8080, some times you might want to change it so that it listens on different HTTP port. I wanted to get Jetty to listen on different port and this is how i configured it

<plugin>
  <groupId>org.mortbay.jetty</groupId>
  <artifactId>jetty-maven-plugin</artifactId>
  <version>7.4.5.v20110725</version>
  <configuration>
    <scanIntervalSeconds>10</scanIntervalSeconds>
    <webAppConfig>
      <contextPath>/ManageContact</contextPath>
    </webAppConfig> 

    <connectors>
      <connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
        <port>9000</port>
        <maxIdleTime>60000</maxIdleTime>
      </connector>

    </connectors>
  </configuration>
</plugin>
In this code the connectors element is used for configuring the new port number, in my case i changed it to use port 9000. In the version 6.1 code you would have to configure Jetty like this, name of the SelectorChannelConnector package was different before it was moved to eclipse

<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>20080</port>
</connector>
</connectors>

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

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.

Debugging your code using Embedded Jetty in Maven

In the Using Embedded Jetty server post i blogged about how to use Embedded Jetty Server using Maven, I wanted to debug one issue in this configuration and i followed these steps to do that
  1. First start the server using mvndebug.bat jetty:run instead of using mvn.bat jetty:run. Please note that i am using Maven 3.0, if you dont have mvndebug then you can just open mvn.bat/.sh in notepad and uncommen this line and then use mvn jetty:run @REM set MAVEN_OPTS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000
    By default the Jetty server will start with suspended=y, which means the server would wait on the first line till you attach to it from Eclipse, if you dont want that you can set suspend=y
  2. Next in your Eclipse, start debug using remote attach and attach localhost port 8000 like this
  3. Next setup break points and hit the URL which would invoke the code that you want to debug and you would see that that Eclipse prompts you once the break point is hit like this

Using Embedded Jetty server

Recently i started using Embedded Maven Jetty plugging during development, it makes development so easy and simple. For example take a look at Hello Embedded Server sample, which is a Sample Servlet 3.0 compliant servlet that uses pom.xml(Maven build file) 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 
  ttp://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.webspherenotes.embedded</groupId>
  <artifactId>HelloEmbeddedServer</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Hello Embedded server Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.0.1</version>
    </dependency>
  </dependencies>
  <build>
    <finalName>HelloEmbeddedServer</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>8.1.2.v20120308</version>
        <configuration>
          <scanIntervalSeconds>10</scanIntervalSeconds>
          <webApp>
            <contextPath>/HelloEmbeddedServer</contextPath>
          </webApp>
        </configuration>
      </plugin>

    </plugins>
  </build>
</project>
Now all that i have to do is execute mvn jetty:run and it takes care of compiling the app and deploying it in Jetty server. The default configuration of this plugin would assume that your target classes are available in <projectrootdirectory>/target/classes, and read classes from that directory and use them, so we dont have to build the .war file, instead you can keep working with the expanded version. Now if you use mvn eclipse:eclipse to setup your project in the Eclipse IDE then you will notice that your project is setup to generate .class files in <projectrootdirectory>/target/classes folder like this
In my case i did setup scanIntervalSeconds attribute with value equal to 10 which tells Maven Jetty plugin to scan <projectrootdirectory>/target/classes directory and reinitialize the app if something has changed. By default whenever i make changes and save them Eclipse will recompiling the .java file and copy classes into <projectrootdirectory>/target/classes directory, and those changes would get picked up automatically in 10 seconds.