Thursday, October 31, 2013

Configure Web, REST and Web Service from a single application using Spring

Now, you have your web application ready and you have deployed it on the cloud. Your website has some viewers. Now comes Ms. Sharma to tell you, "Hey the look and feel of your web site is not good at all. Why don't you put some pink flowery image background and your site will attract more lady customers."
Now, its a cool approach you are going to implement, now again Mr. Kundu has some views on your application and he sends a mail, "Hey can you put some corporate looks in your website. It would be good to attract corporate customers as well'."

Now what, are you going Ms. Sharma way and put some images in your web site background or you are going with Mr. Kundu with some BlueSky theme ?

Now, I have my own way, I would have given them WS and REST exposures and ask them to create their own interfaces or I myself would have created different versions using the same business layer.

If you are not aware of them, you can read them. There are plenty of resources explaining them in minute detail.

Or may be your business requirement is something where you should have a web app, an android app and also an exposure for other clients (Like Windows Phone, ASP.NET  etc). What you are going to do in this situation ?
Mostly you can do, create different applications one for web, another for Web Service and another for REST. But that has a problem too, if you make a change in business, you have to change in all the 3 areas, code re-usability is in question. Other way around could be, install the business logic as separate jar and use it all the 3 applications. But some Cloud account has restrictions of limited application hosting (like Openshift has a restriction of only 3 for a free account). Of course you can buy some space on cloud but for most of the development or simple use case scenarios, I think you are not going to invest a lot.

So, what ?
What about exposing all your applications in a single build.

Yeah you can do that with help of Spring. There may be other way around leaving Spring too. But this one worked for me and it was easy to setup.

Its all about working with 3 different servlets in web.xml and configuring 3 Spring applications. So, the implementation part I am not going into detail, just going through the configuration.

Classpath Dependencies:
I am using JSF as web app and Spring WS and Spring RS. So, I got 31 dependencies in my system. You may have some more or less and if you are reading this section, you are advanced enough to determine which one to keep and which one to remove. Here are my dependencies,

antlr-2.7.7.jar
commons-logging-1.1.1 (1).jar
dom4j-1.6.1.jar
el-impl-2.2.1-b05.jar
hibernate-commons-annotations-4.0.5.Final.jar
hibernate-core-4.3.7.Final.jar
hibernate-jpa-2.1-api-1.0.0.Final.jar
hsqldb.jar
jandex-1.1.0.Final.jar
javassist-3.18.1-GA.jar
jboss-logging-3.1.3.GA.jar
jboss-logging-annotations-1.2.0.Beta1.jar
jboss-transaction-api_1.2_spec-1.0.0.Final.jar
jsf-api-2.2.8-02.jar
jsf-impl-2.2.8-02.jar
jstl-1.2.jar
primefaces-4.0.jar
spring-aop-4.1.3.RELEASE.jar
spring-beans-4.1.3.RELEASE.jar
spring-context-4.1.3.RELEASE.jar
spring-context-support-4.1.3.RELEASE.jar
spring-core-4.1.3.RELEASE.jar
spring-expression-4.1.3.RELEASE.jar
spring-jdbc-4.1.3.RELEASE.jar
spring-orm-4.1.3.RELEASE.jar
spring-tx-4.1.3.RELEASE.jar
spring-web-4.1.3.RELEASE.jar
spring-webmvc-4.1.3.RELEASE.jar
jdom-2.0.2.jar
spring-ws-core-2.2.0.RELEASE.jar
wsdl4j-1.6.2.jar

Please choose accordingly and carefully, otherwise you will end up having ClassNotFoundException.

Now with that, we are moving forward with our web.xml changes.

Configure different exposure in web.xml
In Spring, Simple web app and REST both are handled by DispatcherServlet only while Web Services are handled by MessageDispatcherServlet. So, you don't have to worry about Web Service and REST/Web App.

But you will be in problem while configuring REST and Web App. It is the most important part.
You can try different url pattern mapping with the same servlet and handle them in controller. But, I got errors in this way too and its really painful to handle REST and Web App mapping in controllers. Cause, they behave in the same way.

So, what's the way out ?
Just extend DispatcherServlet and create a dummy servlet that does nothing except making itself a DispatcherServlet. Here is a sample.

 /**  
  *   
  */  
 package servlet;  
 import org.springframework.web.servlet.DispatcherServlet;  
 /**  
  * @author palash.k  
  *   
  */  
 public class RestDispatcher extends DispatcherServlet{  
      /**  
       *   
       */  
      private static final long serialVersionUID = 5153026121972664690L;  
 }  

And you put this in web.xml for your REST controllers.
 <?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"  
      id="WebApp_ID" version="2.5">  
      <display-name>PrimeFaces Web Application</display-name>  
      <context-param>  
     <param-name>contextConfigLocation</param-name>  
     <param-value>  
       /WEB-INF/resources/context.xml  
     </param-value>  
   </context-param>  
      <listener>  
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
   </listener>  
   <listener>  
     <listener-class>  
       org.springframework.web.context.request.RequestContextListener  
     </listener-class>  
   </listener>  
      <!-- WEB Application -->  
       <servlet>  
     <servlet-name>web</servlet-name>  
     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
     <load-on-startup>1</load-on-startup>  
   </servlet>  
   <servlet-mapping>  
     <servlet-name>web</servlet-name>  
     <url-pattern>/web/*</url-pattern>  
   </servlet-mapping>  
   <servlet-mapping>  
     <servlet-name>web</servlet-name>  
     <url-pattern>*.jsp</url-pattern>  
   </servlet-mapping>

<!-- REST Service --> <servlet> <servlet-name>rest</servlet-name> <servlet-class>servlet.RestDispatcher</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>rest</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping> <!-- Web Service --> <servlet> <servlet-name>webService</servlet-name> <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class> <init-param> <param-name>transformWsdlLocations</param-name> <param-value>true</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>webService</servlet-name> <url-pattern>/service/*</url-pattern> </servlet-mapping> </web-app>

Configure 3 different Spring applications:

web-servlet.xml
 <beans xmlns="http://www.springframework.org/schema/beans"  
      xmlns:context="http://www.springframework.org/schema/context"  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="  
     http://www.springframework.org/schema/beans     
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
     http://www.springframework.org/schema/context   
     http://www.springframework.org/schema/context/spring-context-3.0.xsd">  
      <import resource="resources/context.xml" />  
      <context:component-scan base-package="controllers" />  
      <bean  
           class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
           <property name="prefix">  
                <value>/WEB-INF/jsp/</value>  
           </property>  
           <property name="suffix">  
                <value>.jsp</value>  
           </property>  
      </bean>  
 </beans>  

rest-servlet.xml

 <beans xmlns="http://www.springframework.org/schema/beans"  
      xmlns:context="http://www.springframework.org/schema/context"  
      xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context   
     http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">  
      <context:component-scan base-package="rest" />  
      <mvc:annotation-driven />  
 </beans>  

webService-servlet.xml

 <beans xmlns="http://www.springframework.org/schema/beans"  
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
      xmlns:sws="http://www.springframework.org/schema/web-services"  
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
  http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd  
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">  
      <context:component-scan base-package="ws" />  
      <sws:annotation-driven />  
      <sws:dynamic-wsdl id="person" portTypeName="Person"  
           locationUri="/service/Person/" targetNamespace="urn:assistant:1.0:person"  
           requestSuffix="Request" responseSuffix="Response">  
           <sws:xsd location="classpath:xsd/person.xsd" />  
      </sws:dynamic-wsdl>  
 </beans>  



Now, that's it. You now have configured your web app, Spring WS and Spring RS in a single app.

Palash Kanti Kundu

Wednesday, October 30, 2013

Step by step configuration of Hibernate, Spring MVC, Primefaces

So, you have decided to use Spring, Hibernate and Primefaces in your application. I am very much fond of each one of them cause, all of them very easy to use and open source. I use all of them in my own application.
But, the first time I tried to configure them in my application, I had nightmare. The most tough part was to configure Hibernate with Spring and to find how to use Spring beans in Managed Beans. But now my application is stable and development has become easy for me now.
So, I thought of sharing the knowledge to configure the application to use all of them.
I will use HSQL as DB for this post. I assume that you are capable of configuring your DB in the configuration files. Because, you are reading this post means, you are an advanced Java Developer.

Prerequisite
1.     You have knowledge on Spring, Hibernate and JSF and know the basics of setting them up individually
2.     Knowledge of Eclipse IDE or Maven or any other build tool
3.     Working database
4.     Hibernate 4 and Spring 4 (For another pair of these, generally these configuration needs a little change in the session factory configuration, which you can figure out in ease)
5.     Primefaces (3 or 4) and Spring(3 or 4)
This pair can have any combination. Choose any. Spring versioons are compatible with Primefaces versions.
Configuration
 I will go step by step for the configurations.


1. Mention the required libraries in your build - Required library list is huge cause Spring, Hibernate and Primefaces depend on different libraries. So please be careful otherwise you will get many exceptions. There are total 28 dependencies in total.
§  antlr-2.7.7.jar
§  commons-logging-1.1.1.jar
§  dom4j-1.6.1.jar
§  el-impl-2.2.1-b05.jar
§  hibernate-commons-annotations-4.0.5.Final.jar
§  hibernate-core-4.3.7.Final.jar
§  hibernate-jpa-2.1-api-1.0.0.Final.jar
§  hsqldb.jar
§  jandex-1.1.0.Final.jar
§  javassist-3.18.1-GA.jar
§  jboss-logging-3.1.3.GA.jar
§  jboss-logging-annotations-1.2.0.Beta1.jar
§  jboss-transaction-api_1.2_spec-1.0.0.Final.jar
§  jsf-api-2.2.8-02.jar
§  jsf-impl-2.2.8-02.jar
§  jstl-1.2.jar
§  primefaces-4.0.jar
§  spring-aop-4.1.3.RELEASE.jar
§  spring-beans-4.1.3.RELEASE.jar
§  spring-context-4.1.3.RELEASE.jar
§  spring-context-support-4.1.3.RELEASE.jar
§  spring-core-4.1.3.RELEASE.jar
§  spring-expression-4.1.3.RELEASE.jar
§  spring-jdbc-4.1.3.RELEASE.jar
§  spring-orm-4.1.3.RELEASE.jar
§  spring-tx-4.1.3.RELEASE.jar
§  spring-web-4.1.3.RELEASE.jar
§  spring-webmvc-4.1.3.RELEASE.jarWith all these dependencies, WebContent/WEB-INF/lib looks like

2.       Setup JSF for your application
Dependency declaration is complete. The next step is to setup Faces for your application.
In your web.xml mention faces servlet and the extensions you want to map with JSF and run your server. It should be working.
If not, then delete the web.xml and retry. Here is one sample for ease.




 <?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"  
      id="WebApp_ID" version="2.5">  
      <display-name>PrimeFaces Web Application</display-name>  
      <!-- Change to "Production" when you are ready to deploy -->  
      <context-param>  
           <param-name>javax.faces.PROJECT_STAGE</param-name>  
           <param-value>Development</param-value>  
      </context-param>  
      <!-- Welcome page -->  
      <welcome-file-list>  
           <welcome-file>faces/index.xhtml</welcome-file>  
      </welcome-file-list>  
      <!-- JSF mapping -->  
      <servlet>  
           <servlet-name>Faces Servlet</servlet-name>  
           <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>  
           <load-on-startup>1</load-on-startup>  
      </servlet>  
      <!-- Map these files with JSF -->  
      <servlet-mapping>  
           <servlet-name>Faces Servlet</servlet-name>  
           <url-pattern>/faces/*</url-pattern>  
      </servlet-mapping>  
      <servlet-mapping>  
           <servlet-name>Faces Servlet</servlet-name>  
           <url-pattern>*.jsf</url-pattern>  
      </servlet-mapping>  
      <servlet-mapping>  
           <servlet-name>Faces Servlet</servlet-name>  
           <url-pattern>*.faces</url-pattern>  
      </servlet-mapping>  
      <servlet-mapping>  
           <servlet-name>Faces Servlet</servlet-name>  
           <url-pattern>*.xhtml</url-pattern>  
      </servlet-mapping>  
 </web-app>  

3.       Add Spring MVC to Faces
Now, add Spring MVC to your faces application. You have to include  Spring context file as context-param with param name contextConfigLocation and RequestContextListener and ContextLoaderListener as your application listener.
So, basically you have to add three more tags in your web.xml.
Now, it’s time to write faces-config.xml. Here you mention SpringBeanFacesELResolver as the EL Resolver for your faces application.
After adding these, restart the server to check if configuration is working.


 <context-param>  
     <param-name>contextConfigLocation</param-name>  
     <param-value>  
       /WEB-INF/resources/context.xml  
     </param-value>  
   </context-param>  
      <listener>  
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
   </listener>  
   <listener>  
     <listener-class>  
       org.springframework.web.context.request.RequestContextListener  
     </listener-class>  
   </listener>  

This is the faces-config file
 <?xml version="1.0" encoding="utf-8"?>  
 <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>  
           <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>  
      </application>  
 </faces-config>  

4.       Add Hibernate to Spring
In your context file, DriverManagerDataSource as data source, hibernate4.LocalSessionFactoryBean as sessionFactory and use this in your DAO classes. Add POJO, hibernate configurations and mappings etc in the project.
Again restart the server and it is in complete configuration.


 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemalocation="http://www.springframework.org/schema/beans  
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  
      <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">  
           <property name="driverClassName" value="org.hsqldb.jdbc.JDBCDriver">  
           <property name="url" value="jdbc:hsqldb:hsql://localhost:1521/opt/db">  
           <property name="username" value="SA">  
           <property name="password" value="">  
      </property></property></property></property></bean>  
      <bean class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" id="sessionFactory">  
           <property name="dataSource" ref="dataSource">  
           <property name="configLocation" value="classpath:hibernate.cfg.xml">  
      </property></property></bean>  
      <bean class="dao.EmployeeDaoImpl" id="employeeDAO">  
           <property name="sessionFactory" ref="sessionFactory">  
      </property></bean>  
      <bean class="service.EmployeeService" id="service">  
           <property name="dao" ref="employeeDAO">  
      </property></bean>  
 </beans>  

Hibernate configuration
 <?xml version="1.0" encoding="utf-8"?>  
 <!DOCTYPE hibernate-configuration SYSTEM   
 "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">  
 <hibernate-configuration>  
      <session-factory>  
           <property name="hibernate.dialect">  
                org.hibernate.dialect.HSQLDialect  
           </property>  
           <property name="hibernate.connection.driver_class">  
                org.hsqldb.jdbc.JDBCDriver  
           </property>  
           <!-- Assume test is the database name -->  
           <property name="hibernate.connection.url">  
                jdbc:hsqldb:hsql://localhost:1521/opt/db  
           </property>  
           <property name="hibernate.connection.username">  
                SA  
           </property>  
           <property name="hibernate.connection.password">  
           </property>  
           <!-- List of XML mapping files -->  
           <mapping resource="resources/Employee.hbm.xml" />  
      </session-factory>  
 </hibernate-configuration>  

Mapping
 <?xml version="1.0" encoding="utf-8"?>  
 <!DOCTYPE hibernate-mapping PUBLIC   
  "-//Hibernate/Hibernate Mapping DTD//EN"  
  "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">   
 <hibernate-mapping>  
   <class name="bean.Employee" table="EMPLOYEE">  
    <meta attribute="class-description">  
      This class contains the employee detail.   
    </meta>  
    <id name="sapCode" type="int" column="sap_code">  
      <generator class="native"/>  
    </id>  
    <property name="firstName" column="first_name" type="string"/>  
    <property name="lastName" column="last_name" type="string"/>  
    <property name="middleName" column="middle_name" type="string"/>  
   </class>  
 </hibernate-mapping>  

5.   Retrieve Spring beans in Managed Beans
All the setup is complete. To retrieve Spring beans, in your Managed beans, use @ManagedProperty on attributes.

 package managedbeans;  
 import javax.faces.bean.ManagedBean;  
 import javax.faces.bean.ManagedProperty;  
 import service.EmployeeService;  
 @ManagedBean(name = "editor")  
 public class EditorBean {  
      @ManagedProperty(name = "service", value = "#{service}")  
      private EmployeeService service;  
      private String value = "Editor";  
      /**  
       * @return the value  
       */  
      public String getValue() {  
           return value;  
      }  
      /**  
       * @param value  
       *      the value to set  
       */  
      public void setValue(String value) {  
           this.value = value;  
      }  
      /**  
       * @return the service  
       */  
      public EmployeeService getService() {  
           return service;  
      }  
      /**  
       * @param service  
       *      the service to set  
       */  
      public void setService(EmployeeService service) {  
           this.service = service;  
      }  
      public void save() {  
           System.out.println("Using service");  
           System.out.println(getValue());  
           System.out.println(service.getEmployees());  
      }  
 }  


Enjoy the development with these components. They are really cool stuffs.

I've complete websites built on top of these three only. They really are helpful for faster development, better maintainability, less coding, good looking GUI. You are free to take a look in the below locations,

https://assistant-palash90.rhcloud.com/req-resp.asst

https://temperatureconverter-palash90.rhcloud.com/


That's it. If anything breaks, in between, you can post comment, I will check and revert back.

If this helped you out, you can share this in your network as well. Sharing is caring...


Next
Palash Kanti Kundu