Thursday, February 20, 2014

Simple JAX-RS Service

If you have a fundamental grasp of Java and want to learn how to build REST services "RESTful Java with JAX-RS 2.0" is an excellent book for you. 

After reading few chapters, I realized that REST is definitely not just new technology, it's whole new concept and thought about designing enterprise application. Thinking about integration, in REST way definitely going to make you feel exciting. 

I was reading Chapter 3, thought of sharing some knowledge about creating a simple REST service. I may not be able to provide more details about REST concepts in this blog, I would rather recommend/suggest to read some books or some detailed articles. 

Designing RESTful Services is a 4 step process:

1) Define Object Model
   Design Object/Class diagram and identify entities.

2) Model the URI
   First thing for creating distributed interface is to define and name your service endpoints.

3) Defining the data format
In this step you basically design your data structure, for example, XML structure for 'Create Order' service call.

4) Assigning HTTP method (think aboutt operation to be performed on Resources identified in Step 2 above

In this example, we're creating a 'Consumer Entry' service with 3 operations:
- Create Consumer
- Update Consumer
- Retrieve Consumer

1) My Object Model below, a simple POJO.

public class Customer {
   private int id;
   private String firstName;
   private String lastName;
   private String street;
   private String city;
   private String state;
   private String zip;
   private String country;

   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }
... //other accessors
}

2) Model the URI
In this step you assign URI to your resources; we have just one resource that simplify things. i'm going to create a URL '/customers' for this resource.

3) Defining the data format
In this step, you need to define your data structure to be exchanged over wire, for our example, it's:

<customer id="2">
   <first-name>Andy</first-name>
   <last-name>Reeves</last-name>
   <street>3232 Delaware Street</street>
   <city>Atlanta</city>
   <state>GA</state>
   <zip>39116</zip>
   <country>USA</country>
</customer>

4) Assigning HTTP method (think about operation to be performed on Resources identified in Step 2 above)

We're going to design a service with 3 operation, and we need to think about what HTTP method would apply to these operations. 

- Retrieve Consumer: For this operation we could assign a 'GET' HTTP method on our resource
- Create Consumer: For this operation we could assign a 'POST' or 'PUT' HTTP method. Ideally we use 'POST' for create operations and 'PUT' for update. Read more about this here
- Update Consumer: As I mentioned above, we can assign 'PUT' to our resource.

Theory over.. code magic begins.

Below is my Service class. This is straight from the book, did a little modification by adding '@Singleton' on class because I wanted to store the data after every request, and I didn't want container to create a new instance of my service class for every request. There are bettrer ways of achieving this in REST.Read more about Application.java here.

Author decided to keep things very basic, because of which we ended up marshalling and unmarshalling XML through DOM and creating a static representation of response data.  You can see 3 methods for each of my operation.

CustomerResource.java  (Service Class)
@Singleton
@Path("/customers")
public class CustomerResource {
private Map<Integer, Customer> customerDB = new ConcurrentHashMap<Integer, Customer>();
private AtomicInteger idCounter = new AtomicInteger();

public CustomerResource() {
}

@POST
@Consumes("application/xml")
public Response createCustomer(InputStream is) {
System.out.println("Inside POST createCustomer");
Customer customer = readCustomer(is);
customer.setId(idCounter.incrementAndGet());
System.out.println("Setting id to " + customer.getId());
customerDB.put(customer.getId(), customer);
System.out.println("Created customer " + customer.getId());
Response res = Response.created(
URI.create("customers/" + customer.getId())).build();
return res;
        }

@GET
@Path("{id}")
@Produces("application/xml")
public StreamingOutput getCustomer(@PathParam("id") int id) {
final Customer customer = customerDB.get(id);
if (customer == null) {
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
return new StreamingOutput() {
public void write(OutputStream outputStream) throws IOException,
WebApplicationException {
System.out.println(outputStream.getClass().getName());
outputCustomer(outputStream, customer);
}
};
}

@PUT
@Path("{id}")
@Consumes("application/xml")
public void updateCustomer(@PathParam("id") int id, InputStream is) {
Customer update = readCustomer(is);
Customer current = customerDB.get(id);
if (current == null)
throw new WebApplicationException(Response.Status.NOT_FOUND);

current.setFirstName(update.getFirstName());
current.setLastName(update.getLastName());
current.setStreet(update.getStreet());
current.setState(update.getState());
current.setZip(update.getZip());
current.setCountry(update.getCountry());
}

protected void outputCustomer(OutputStream os, Customer cust)
throws IOException {
PrintStream writer = new PrintStream(os);
writer.println("<customer id=\"" + cust.getId() + "\">");
writer.println("   <first-name>" + cust.getFirstName()
+ "</first-name>");
writer.println("   <last-name>" + cust.getLastName() + "</last-name>");
writer.println("   <street>" + cust.getStreet() + "</street>");
writer.println("   <city>" + cust.getCity() + "</city>");
writer.println("   <state>" + cust.getState() + "</state>");
writer.println("   <zip>" + cust.getZip() + "</zip>");
writer.println("   <country>" + cust.getCountry() + "</country>");
writer.println("</customer>");
}

protected Customer readCustomer(InputStream is) {
try {
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
Document doc = builder.parse(is);
Element root = doc.getDocumentElement();
Customer cust = new Customer();
if (root.getAttribute("id") != null
&& !root.getAttribute("id").trim().equals(""))
cust.setId(Integer.valueOf(root.getAttribute("id")));
NodeList nodes = root.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
Element element = (Element) nodes.item(i);
if (element.getTagName().equals("first-name")) {
cust.setFirstName(element.getTextContent());
} else if (element.getTagName().equals("last-name")) {
cust.setLastName(element.getTextContent());
} else if (element.getTagName().equals("street")) {
cust.setStreet(element.getTextContent());
} else if (element.getTagName().equals("city")) {
cust.setCity(element.getTextContent());
} else if (element.getTagName().equals("state")) {
cust.setState(element.getTextContent());
} else if (element.getTagName().equals("zip")) {
cust.setZip(element.getTextContent());
} else if (element.getTagName().equals("country")) {
cust.setCountry(element.getTextContent());
}
}
return cust;
} catch (Exception e) {
throw new WebApplicationException(e, Response.Status.BAD_REQUEST);
}
}

}


Server
After using JAX-WS, I always thought of deploying my REST web services through command line client. I'm using grizzly as containe. Calling 'start()' in Main.java will start an instance of grizzly.

public class Main {
    // Base URI the Grizzly HTTP server will listen on
    public static final String BASE_URI = "http://localhost:8080/services";

    /**
     * Starts Grizzly HTTP server exposing JAX-RS resources defined in this application.
     * @return Grizzly HTTP server.
     */
    public static HttpServer startServer() {
        // create a resource config that scans for JAX-RS resources and providers
        // in com.example package
        final ResourceConfig rc = new ResourceConfig().packages("com.restfully.shop.services");

        // create and start a new instance of grizzly http server
        // exposing the Jersey application at BASE_URI
        return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
    }

    /**
     * Main method.
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        final HttpServer server = startServer();
        System.out.println(String.format("Jersey app started with WADL available at "
                + "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
        System.in.read();
        server.stop();
    }

}

Test Client
I'm simply creating a Customer and retrieving it from my service.

public class ServiceTester {
public static void main(String args[]){
        Client c = ClientBuilder.newClient();
        WebTarget target = c.target("http://localhost:8080/services");
        target = target.path("/customers");
        Invocation.Builder requestBuilder = target.request();
        
        String xml = "<customer>"
                + "<first-name>Bill</first-name>"
                + "<last-name>Burke</last-name>"
                + "<street>256 Clarendon Street</street>"
                + "<city>Boston</city>"
                + "<state>MA</state>"
                + "<zip>02115</zip>"
                + "<country>USA</country>"
                + "</customer>";

        Response response = requestBuilder.post(Entity.xml(xml));
        if (response.getStatus() != 201) throw new RuntimeException("Failed to create");
        String location = response.getLocation().toString();
        System.out.println("Location: " + location);
        response.close();

        String responseStr = c.target(location).request().get(String.class);// java.lang.String is response entity class
        System.out.println("Response is : "+ responseStr);

}

pom.xml
Grizzly has lot of depenmdencies, you can use this pom file to download them.

<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/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>simple-service</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>simple-service</name>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.glassfish.jersey</groupId>
                <artifactId>jersey-bom</artifactId>
                <version>${jersey.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-grizzly2-http</artifactId>
        </dependency>
        <!-- uncomment this to get JSON support:
         <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-moxy</artifactId>
        </dependency>
        -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <inherited>true</inherited>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <mainClass>com.example.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <properties>
        <jersey.version>2.4.1</jersey.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

Overall it was simple to design except the marshalling/unmarshalling piece, and integrating Grizzly with book examples. Anyways, happy reading, drop me a comment, if you've any question.


Monday, February 17, 2014

A Simple JSF Application

I’m creating a Bill-Pay application that

- Display a login screen
- After successful login, displays list of all available Payee in system
- User can select relevant payees from the list / ignore them\
- Add selected payees in their profile

My first facelet (Login.xhtml) displays a web page with two input fields, Login and Password. I’m using JSF standards validation mechanism to validate these fields, appropriate error message will be displayed if any of these fields fail validation.

System will also display appropriate error message if authentication fails. Upon successful login, next screen will display list of available Payee in the application.

Login.xhtml:
<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">
<h:head>
       <h:outputStylesheet libary="css" name="default.css" />
       <title>Login</title>
</h:head>
<h:body>
       <h:form>
              <h:graphicImage library="images" name="wave.med.gif"
                     alt="Duke waving his hand" />
              <p>
                     <h:outputText value="#{bundle.userNameLabel}"/>
                     <h:inputText id="userName" title="Enter user id"
                           value="#{userAuthenticationBean.userName}">
                           <f:validateRequired/>
                           <f:validateLength minimum="#{userAuthenticationBean.minLengthUserName}" maximum="#{userAuthenticationBean.maxLengthUserName}"/>
                     </h:inputText>
              </p>  
              <h:message showSummary="true" showDetails="false"
                     style="color: #d20005;
                     font-family: 'New Century Schoolbook', serif;
            font-style: oblique;
            text-decoration: overline"
                     id="errors1" for="userName" />
              <p>   
                     <h:outputText value="#{bundle.passwordLabel}"/>
                     <h:inputSecret id="password" titl="Enter password"
                           value="#{userAuthenticationBean.password}">
                           <f:validateRequired/>
                     </h:inputSecret>                        
              </p>
              <h:message showSummary="true" showDetails="false"
                     style="color: #d20005;
                     font-family: 'New Century Schoolbook', serif;
            font-style: oblique;
            text-decoration: overline"
                     id="errors2" for="password" />
              <p>
                     <h:commandButton id="submit" value="Submit" action="showPayeeList" />
              </p>
       </h:form>
</h:body>
</html>

At this point, I created a Managed Bean (UserAuthenticationBean.java) to perform authentication.

UserAuthenticationBean.java
package billpay.web.consumer;

import java.io.Serializable;
import java.util.Random;

import javax.enterprise.context.SessionScoped;
import javax.inject.Named;


@Named
@SessionScoped
public class UserAuthenticationBean implements Serializable{

                private static final long serialVersionUID = 5443351151396868724L;
   
                public int MinLengthUserName=4;
                public int MaxLengthUserName=10;
               
                private String userName;
       private String password;

       public String getPassword() {
              return password;
       }

       public void setPassword(String password) {
              this.password = password;
       }

                public String getUserName() {
                                return userName;
                }

                public void setUserName(String userName) {
                                this.userName = userName;
                }
}


At this point, when I compiled my application, everything looked good, however deployment failed with below error:

org.jboss.weld.exceptions.DefinitionException: WELD-000075 Normal scoped managed bean implementation class has a public field:  [EnhancedAnnotatedFieldImpl] public billpay.web.consumer.UserAuthenticationBean.minLengthUserName
       at org.jboss.weld.bean.ManagedBean.checkBeanImplementation(ManagedBean.java:225)

The reason for this failure was ‘public’ fields in my Bean. After some googling, I looked at this post.

Since I’m using JSF 2, I decided to use omnifaces to import my constants from Bean class. It was quite easy to integrate omnifaces, just drop a jar in WEB-INF/lib, and declare the tag on your facelet.

Read more about Omnifaces here

See changes in my facelet to integrate the omnifaces tags below.

<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:o="http://omnifaces.org/ui"
      xmlns:of="http://omnifaces.org/functions">

<h:body>
<o:importConstants type="billpay.web.consumer.UserAuthenticationBean"/>

                                                <h:inputText id="userName" title="Enter user id"
                                                                value="#{userAuthenticationBean.userName}">
                                                                <f:validateRequired/>
                                                                <f:validateLength minimum="#{UserAuthenticationBean.MinLengthUserName}" maximum="#{UserAuthenticationBean.MaxLengthUserName}"/>

Also I had to make some changes in my Bean class to declare my fields as constants, by making them ‘static’ and ‘final’.

       public static final int MinLengthUserName=4;
       public static final int MaxLengthUserName=10;



I deployed my application successfully in Tomcat, everything looked good and typing this URL (http://localhost:8080/billpay/faces/login.xhtml) in address bar displayed my login facelet.


However I also noticed  that my validation was not working as expected. If I click on Submit without entering any text in Login and Password field, JSF was not throwing any validation error in spite of <f:validateRequired/> tag.

After some reading and scanning APIs, I came to know that we need to add a context parameters that will instruct JSF to perform validation for NULL/EMPTY fields.

       <context-param>
              <param-name>javax.faces.VALIDATE_EMPTY_FIELDS</param-name>
              <param-value>true</param-value>
       </context-param>

See javax.faces.validator.Validator Javadoc for more information.

My next task was to set up authentication.  J2EE tutorial discusses several approaches for implementing this functionality.

Since UserAuthenticationBean  already had login and password values, I added a new method to perform login operation:

       public String login(){
              if(this.userName.equals("Vicky") && this.password.equals("USA")){
                     System.out.println("You're good to go");
                     return "showPayeeList";
              }else{
                     FacesContext context = FacesContext.getCurrentInstance();
                     context.addMessage(null, new FacesMessage("Login failed."));
                     return null;
              }
       }

I also had to make some changes in facelet to invoke this operation for login operation.

<h:commandButton id="submit" value="Submit" action="#{userAuthenticationBean.login}" />

If I enter correct credentials, system will display ‘showPayeeList’ facelt that diplays all available payees in the system, however if authentication fails, system displays Login page again with error message ‘Login failed’.


In my login facelet I didn’t add any <h:messge/> tag to display the error message, however it does that automatically because we’ve set PROJECT_STAGE to ‘Development’.
       <context-param>
              <param-name>javax.faces.PROJECT_STAGE</param-name>
              <param-value>Development</param-value>
       </context-param>


WOW!!

Now my next task  is to display list of all available Payee .

In our application, we usually get list of Payees from database, however to simulate that I created a new RequestScoe ManagedBean (PayeeBean) and an Entity (PayeeEntity) to retrieve list of Payees. For this simple application, there was no need of an Entity, however I wanted to create a layer to separate Presentation and Data layers.

@Named
@RequestScoped
public class PayeeBean implements Serializable{

       private static final long serialVersionUID = 5443352251396868724L;
      
       /**
        * Returns all Payees that exists in Bill Payment system. Ideally this method
        * would refer some EJBs or some other data sourcesin actual application.
        * @return List<PayeeVO>
        * @throws Exception
        */
       public List<PayeeVO> getPayeeList(){
              return PayeeEntity.getPayeeList();
       }
}


public class PayeeEntity {

       public static List<PayeeVO> getPayeeList(){
              List<PayeeVO> payeeList = new ArrayList<PayeeVO>();
              payeeList.add(new PayeeVO(1,"Comcast"));
              payeeList.add(new PayeeVO(2,"Sawnee"));
              payeeList.add(new PayeeVO(3,"Macy's"));
              payeeList.add(new PayeeVO(4,"Walgreens"));
              return payeeList;
       }
}


Once I’ve list of Payees, my next task was to display them on a web page that will allow user to select appropriate payees.

Also this page will have option to ‘Add’ selected Payee in consumer’s profile, or clear the selection.

Since all my Payees were stored in a java.util.List, <h:dataTable> was obvious choice, however I had to display a checkbox for every Payee that will allow users to make selection. Depending upon your requirements, we could also use <ui:repeat> or <c:forEach> to display these values, however I stick with JSF standard components to explore their features.

showPayeeList.xhtml

<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
       xmlns:h="http://java.sun.com/jsf/html"
       xmlns:f="http://java.sun.com/jsf/core">
<h:head>
       <h:outputStylesheet library="css" name="default.css" />
       <title>Payee List</title>
</h:head>
<h:body>
       <h:form>
              <h:dataTable value="#{payeeBean.payeeList}" var="payee">
                     <f:facet name="caption">List of Payee</f:facet>
                     <h:column>
                           <f:facet name="header">Payee's Name</f:facet>
                            #{payee.name}
                            </h:column>
                     <h:column>
                     <f:facet name="header">Add</f:facet>
                           <h:selectBooleanCheckbox
                                  value="#{consumerBean.selectedPayee[payee.id]}" />
                     </h:column>
              </h:dataTable>
              <h:commandButton value="Submit" action="#{consumerBean.showSelectedPayee}" />
              <h:commandButton value="Clear" action="#{consumerBean.clearSelectedPayee}" />
       </h:form>
</h:body>
</html>

I also created a new bean (ConsumerBean) to store these selected values. Also this bean will be stored in Session scope because it holds consumer specific values.

ConsumerBean.java

@Named
@SessionScoped
public class ConsumerBean implements Serializable{

       private static final long serialVersionUID = 5443351151876868724L;
       private Map<Integer, Boolean> selectedPayee = new HashMap<Integer, Boolean>();
       private List<PayeeVO> selectedPayeeList = new ArrayList<PayeeVO>();
       private List<PayeeVO> payeeList = PayeeEntity.getPayeeList();
      
       public Map<Integer, Boolean> getSelectedPayee(){
              return selectedPayee;
       }
      
       public String showSelectedPayee(){
              for(PayeeVO payee: payeeList){
                     if(selectedPayee.get(payee.getId()))
                                  selectedPayeeList.add(payee);
              }
              selectedPayee.clear();
              return "showSelectedPayee";
       }

       public String clearSelectedPayee(){
              selectedPayeeList.clear();
              return null;
       }     
      
       public List<PayeeVO> getSelectedPayeeList(){
              return selectedPayeeList;
       }
}


After successful login, system displays all available Payees (below)



I selected ‘Comcast’ and ‘Sawnee’, clicked on ‘Add’, and here is my next screen

Details of other config files below:

faces-config.xml
<faces-config 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-facesconfig_2_0.xsd"
    version="2.0">
    <application>
        <resource-bundle>
            <base-name>billpay.web.messages.Messages</base-name>
            <var>bundle</var>
        </resource-bundle>
        <locale-config>
            <default-locale>en</default-locale>
            <supported-locale>es</supported-locale>
        </locale-config>
    </application>
</faces-config>

Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.faces</welcome-file>
</welcome-file-list>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.VALIDATE_EMPTY_FIELDS</param-name>
<param-value>true</param-value>
</context-param>
<listener>
<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>
</web-app>

Messages_en.properties
userNameLabel=Login:
passwordLabel=Password:

Workspace


Overall I’m amazed with simplicity offered by JSF. It took me approximately 2 hours to complete this simple application. Thanks for reading.