Spring Integration Webapp( JPA/Hibernate | Webservices (JAX-WS|Apache CXF) | JQuery | EJB3 | Maven | Jboss | Annoatations)

Spring is one of the best Framework’s around in J2EE field which has made integration to various Framework pretty easy. This article is in series of articles which teach about spring integration in details. All source code is checked into svn which can be checked out and tested.

Assumption : Readers has basic knowledge of Servlets and JSP technologies.

Background : Sample project named testspring has been create in modular manner using Maven.  I used 2 differrent database schema names of mysql testjpa/testejb to test this project. I have configured

<property name=”hibernate.hbm2ddl.auto” value=”update” />

so that once proper connectivity is made program on startup will generate all tables in database

Any framework that has to integrated into J2EE frontend technology has to get control from Servlet Container, As all “http”(There can be other requests RMI/JMS..etc) requests are passed on to servlet container first which inturn based on configuration passes to corresponding framework.

All the integrations are generally handle using servlet mapping, or using listeners or filters in Webapplication.

To to integrate spring in webapplication we have to do the following

  • Configure spring Listener and Servlet in web.xml
	<!-- Configuration files for spring  -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
            /WEB-INF/spring/app-config.xml,
            /WEB-INF/spring/app-*-config.xml
        </param-value>
	</context-param>

	<!-- Spring listeners -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<listener>
		<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
	</listener>
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/services/*</url-pattern>
	</servlet-mapping>

Now that you have configured spring now start configuring spring beans in Spring configuration files.( As per the above configuration file. All requests with url pattern services/* will get routed to spring dispatcher servlet. Which inturn takes care of request mapping based on Configuration files or using Annotations.

if you have observerd the spring servlet name is “dispatcher”

so the configuration file that is read by default will be dispatcher-servlet.xml and then other files with same name pattern defined in context-param will get loaded.

Attached is my Dispatcher Servlet Sample code

<?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xsi:schemaLocation="
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />
	<resources mapping="/assets/**" location="/assets/" />
	<resources mapping="/CSS/**" location="/CSS/" />
	<resources mapping="/images/**" location="/images/" />
	<resources mapping="/JS/**" location="/JS/" />
	<resources mapping="/swfupload/**" location="/swfupload/" />
	
	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory 
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>       
    -->

	<!-- freemarker config -->
	<beans:bean id="freemarkerConfig"
		class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
		<beans:property name="templateLoaderPath" value="/WEB-INF/freemarker/" />
		<beans:property name="freemarkerVariables">
			<beans:map>
				<beans:entry key="xml_escape" value-ref="fmXmlEscape" />
			</beans:map>
		</beans:property>
	</beans:bean>

	<beans:bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape" />

	<!--

		View resolvers can also be configured with ResourceBundles or XML
		files. If you need different view resolving based on Locale, you have
		to use the resource bundle resolver.
	-->
	<beans:bean id="viewResolver"
		class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
		<beans:property name="cache" value="true" />
		<beans:property name="prefix" value="" />
		<beans:property name="suffix" value=".html" />

		<!--
			if you want to use the Spring FreeMarker macros, set this property to
			true
		-->
		<beans:property name="exposeSpringMacroHelpers" value="true" />

	</beans:bean>
    
       
       
</beans:beans>

Above code has Configuration to define view resolver (We can integrate different View Technologies in it JSP/Freemarker/Velocity…etc). I’m using freemarker in my example. It also has a commented code which uses jsp as view resolver

The above configuration is basic configuration for Spring MVC. If you have observed it we have defined that spring should discover beans by itself based on annotations rather than configuration stuff. Annotations make is easier for developer to define beans avoiding unnecessary xml configuration which is difficult to remember

Above configuration also lists out url pattern’s that have to be excluded in this flow (Example all css/js/images etc files ).

Below is same Spring MVC controller which is configured through annotations

C:\development\linkwithweb\svn\SpringTutorials\testspring\images

/*
 * Copyright 2011 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.northalley.template.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;

import com.northalley.template.services.WelcomeService;

/**
 * @author ashwin kumar
 * 
 */
@Controller
public class GenericController {

	@Autowired
	@Qualifier("welcomeService")
	private WelcomeService welcomeService;

	/**
	 * Constructor
	 */
	public GenericController() {
	}

	/**
	 * @param searchCriteria
	 * @param formBinding
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/test", method = RequestMethod.POST)
	@ResponseBody
	public Response search(SearchCriteria searchCriteria,
			BindingResult formBinding, WebRequest request) {
		Response response = new Response();
		response.setWelcome(welcomeService.hello("Ashwin"));

		return response;
	}

	@RequestMapping("/freemarkertest")
	public ModelAndView hello() {
		return new ModelAndView("hello", "greeting", "Hello world!");
	}

}

If you look into the code it defines that this class is a Spring MVC Controller(Class that handles all requests)

All the methods that you want to expose in this class should get a RequestMapping annotation with URL pattern and corresponding attributes defined for that

Ex:@RequestMapping(value = “/test”, method = RequestMethod.POST)   (This says any URL with services/test has to be handled by this method).. “services” is base url for spring requests which is configured in web.xml

You can directly render response from here using ResponseBody annotation or you can create model object and pass it to View Technology to render that by creating ModelAndView as response object

In the above example i have @ResponseBody annotation configured for one method and i have configured to receive JSON repsonse for any ResponseBody annotation in my app-config.xml

	<!--
		Define the OXM marshaller which is used to convert the Objects <->
		JSON/XML.
	-->
	<beans:bean id="oxmMarshaller"
		class="org.springframework.oxm.xstream.XStreamMarshaller" />

	<beans:bean id="marshallingHttpMessageConverter"
		class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
		<beans:property name="marshaller" ref="oxmMarshaller" />
		<beans:property name="unmarshaller" ref="oxmMarshaller" />
	</beans:bean>

	<!--
		Required for REST services in order to bind the return value to the
		ResponseBody.
	-->
	<beans:bean
		class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
		<beans:property name="messageConverters">
			<util:list id="beanList">
				<ref bean="marshallingHttpMessageConverter" />
			</util:list>
		</beans:property>
	</beans:bean>

Here is sample Spring MVC Design

Read more about spring MVC in

 

http://static.springsource.org/spring/docs/2.0.x/reference/mvc.html

The below one is one of best link which explains all different way you can use Rest Style URL in Spring MVC

http://blog.springsource.com/2009/03/08/rest-in-spring-3-mvc/

 

Now that i have given basic Introduction to Spring MVC integration i’ll take you through JPA Configuration both in Tomcat as well as JBOSS.

JPA can be used in 2 ways ( Using Spring and Using EJB3 container) . As we don’t have EJB container in tomcat we use spring to configure JPA for us.

Let me start with JPA/Hibernate  using Spring in tomcat

I have configured JPA in app-jpa-config.xml in testspring-webapp/WEB-INF/spring   folder (Checkout code from svn to see project structure)

Here is snippet of the JPA config file

<?xml version="1.0" encoding="UTF-8"?>


<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">


	<tx:annotation-driven transaction-manager="transactionManager" />

	<!--
        Data source
    -->
	<beans:bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<beans:property name="driverClassName">
			<beans:value>org.hsqldb.jdbcDriver</beans:value>
		</beans:property>
		<beans:property name="url">
			<beans:value>jdbc:hsqldb:mem:testspring-db</beans:value>
		</beans:property>
		<beans:property name="username">
			<beans:value>sa</beans:value>
		</beans:property>
		<beans:property name="password">
			<beans:value></beans:value>
		</beans:property>
	</beans:bean>

	<!--
        Configuration for Hibernate/JPA
    -->
	<beans:bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<beans:property name="persistenceUnitName" value="testspring-jpa" />
		<beans:property name="dataSource" ref="dataSource" />
		<beans:property name="jpaDialect">
			<beans:bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
		</beans:property>
		<beans:property name="jpaVendorAdapter">
			<beans:bean
				class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
				<beans:property name="showSql" value="false" />
				<beans:property name="generateDdl" value="true" />
				<beans:property name="databasePlatform"
					value="org.hibernate.dialect.HSQLDialect" />
			</beans:bean>
		</beans:property>
	</beans:bean>

	<beans:bean id="transactionManager"
		class="org.springframework.orm.jpa.JpaTransactionManager">
		<beans:property name="entityManagerFactory" ref="entityManagerFactory" />
		<beans:property name="dataSource" ref="dataSource" />
	</beans:bean>

</beans:beans>

As you see here we have configured persistenceUnitName as “testspring-jpa”. This name has been configured in persistence.xml of  testspring-java project module. Here is the snippet for that

<persistence
  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_1_0.xsd"
  version="1.0">

 <persistence-unit name="testspring-jpa">
 </persistence-unit>

</persistence>

And now that we have configured spring we can create entities in JPA style and use EntityManager to fire our queries.

Here is the sample welcomeService that is used in our Spring MVC controller

/*
  
 */

package org.northalley.template.testspring.services;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.northalley.template.testspring.entities.Welcome;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


@Service("welcomeService")
public class WelcomeServiceImpl implements WelcomeService {

	@PersistenceContext
	private EntityManager entityManager;

	@Transactional
	public Welcome hello(String name) {
		if (name == null || name.trim().length() == 0)
			throw new RuntimeException("Name cannot be null or empty");

		Welcome welcome = null;
		try {
			Query q = entityManager
					.createQuery("select w from Welcome w where w.name = :name");
			q.setParameter("name", name);
			welcome = (Welcome) q.getSingleResult();
		} catch (NoResultException e) {
			welcome = new Welcome();
			welcome.setName(name);
			welcome.setMessage("Welcome " + name);
			entityManager.persist(welcome);
		}
		return welcome;
	}
}

Now Lets switch to other part of using JPA with EJB ( This can be tested in jboss)

Here is sample snippet of stateless session bean in testspring-ejb project that is using JPA to get list of users

package org.testspring.ejb.dao;

import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.testspring.ejb.entity.User;

/**
 * @author ashwin kumar
 * 
 */
@Stateless(mappedName = "userDAOBean")
public class UserDAOBean implements UserDAO {
	private static Log log = LogFactory.getLog(UserDAOBean.class);

	private EntityManager em;

	@PersistenceContext(unitName = "TestEntityManager")
	public void setEm(EntityManager em) {
		this.em = em;
	}

	public List<User> getUsers() {
		log.debug("getUsers");
		List<User> users = this.em.createQuery(
				"select user from User user order by user.lastName")
				.getResultList();
		return users;
	}

	// not using this method in this example app
	public User saveUser(User user) {
		log.debug("saveUser: " + user);
		this.em.persist(user);
		this.em.flush();
		return user;
	}
}

Below is code of User Entity i have created

package org.testspring.ejb.entity;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
//if the table name matches your class name, you don't need the 'name' annotation
@Table(name="lt_user") 
public class User extends BaseEntity {
     
    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    //we don't need the Column annotation here bc the column name and this field name are the same
    private Long id;
    
    @Column(name="first_name",nullable=false,length=50)
    private String firstName;
    
    @Column(name="last_name",nullable=false,length=50)
    private String lastName;
    
    private Date birthday;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
    
    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 Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
 
}

Now that we are done with basic end to end integration .I’ll also show how to inject EJB in Servlet/Spring MVC

Below is sample servlet which called stateless bean . Same method is used in spring MVC too

package com.testspring.servlet;

import java.io.IOException;
import java.util.Hashtable;
import java.util.List;

import javax.ejb.EJB;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.testspring.ejb.dao.UserDAO;
import org.testspring.ejb.entity.User;

import com.testspring.service.MathService;

/**
 * @author ashwin kumar
 * 
 */
public class UserAdminServlet extends HttpServlet {

	@EJB(mappedName = "testspring-ear-0.0.1-SNAPSHOT/UserDAOBean/local")
	private UserDAO userDao;

	WebApplicationContext context = null;


	/**
	 * @param filterConfig
	 * @throws ServletException
	 */
	public void init(ServletConfig filterConfig) throws ServletException {
		System.out.println("Inti calleddddddddddddddd");
		super.init(filterConfig);
		ServletContext servletContext = filterConfig.getServletContext();
		context = WebApplicationContextUtils
				.getWebApplicationContext(servletContext);
		// set up an injected bean into application scope
		// servletContext.setAttribute("mybean", context.getBean("aBean"));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest
	 * , javax.servlet.http.HttpServletResponse)
	 */
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		System.out.println(((MathService) context.getBean("mathService")).add(
				1, 2));

		if (userDao == null) {
			try {
				Hashtable environment = new Hashtable();
				environment.put(Context.INITIAL_CONTEXT_FACTORY,
						"org.jnp.interfaces.NamingContextFactory");
				environment.put(Context.URL_PKG_PREFIXES,
						"org.jboss.naming:org.jnp.interfaces");
				environment.put(Context.PROVIDER_URL, "jnp://localhost:1099"); // remote
				// machine
				// IP

				Context context = new InitialContext(environment);
				userDao = (UserDAO) context
						.lookup("testspring-ear-0.0.1-SNAPSHOT/UserDAOBean/local");
				// context.lookup("userDAOBean");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		doPost(req, resp);
	}

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		List<User> users = userDao.getUsers();
		for (int i = 0; i < users.size(); i++) {
			response.getWriter().append(
					"UserName :" + users.get(i).getFirstName() + " "
							+ users.get(i).getLastName()).append("<br/>");
			response.getWriter().append("id :" + users.get(i).getId()).append(
					"<br/>");
		}
	}
}

 

Now that i have covered all topics from frontend to db, now i’ll take you though how to configure webservices. I’ll show examples with both Apache CXF and JAX-WS

 

Webservices

Similar to spring MVC configuration through servlet , we have to configure both JAX-WS and Apache CXF through their own servlets. Below is servlet configuration to enable them

<!--  jax-ws -->
	<servlet>
		<servlet-name>jaxws-servlet</servlet-name>
		<servlet-class>com.sun.xml.ws.transport.http.servlet.WSSpringServlet</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>jaxws-servlet</servlet-name>
		<url-pattern>/ws/*</url-pattern>
	</servlet-mapping>



<!-- CXF Configuration -->
	<servlet>
		<servlet-name>CXFServlet</servlet-name>
		<servlet-class>
			 org.apache.cxf.transport.servlet.CXFServlet
		</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>CXFServlet</servlet-name>
		<url-pattern>/webservice/*</url-pattern>
	</servlet-mapping>

Now that we have configured respective URL patterns now lets see configuration in Spring that is required to expose Beans as webservices

Webservice configuration for spring is configured in app-ws-config.xml

<?xml version="1.0" encoding="UTF-8"?>

	<!--
	-->

<beans:beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ws="http://jax-ws.dev.java.net/spring/core"
	xmlns:wss="http://jax-ws.dev.java.net/spring/servlet" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:beans="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
        http://jax-ws.dev.java.net/spring/core  http://jax-ws.dev.java.net/spring/core.xsd
        http://jax-ws.dev.java.net/spring/servlet http://jax-ws.dev.java.net/spring/servlet.xsd
        http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">


	<!-- Web service config for Apache CXF -->
	<import resource="classpath:META-INF/cxf/cxf.xml" />
	<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
	<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

	<jaxws:endpoint id="orderProcess"
		implementor="org.northalley.template.testspring.controller.OrderProcessImpl"
		address="/OrderProcess" />

	<!-- Web service config for JAX-WS -->

	<wss:binding url="/ws">
		<wss:service>
			<ws:service bean="#helloWs" />
		</wss:service>
	</wss:binding>


	<beans:bean id="helloWs"
		class="org.northalley.template.testspring.controller.WebserviceController">
	</beans:bean>


</beans:beans>

Below is how i have expose OrderService as webservice for apache CXF

package org.northalley.template.testspring.controller;

import javax.jws.WebService;

@WebService(endpointInterface = "org.northalley.template.testspring.controller.OrderProcess")
public class OrderProcessImpl implements OrderProcess {

    public String processOrder(Order order) {
        return order.validate();
    }
}

Below is code of bean which is exposed by JAX-WS

/*
 * 
 */
package org.northalley.template.testspring.controller;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;

import org.northalley.template.testspring.services.WelcomeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

/**
 * @author ashwin kumar
 * 
 */
@WebService(name = "/hello")
@SOAPBinding(style = SOAPBinding.Style.RPC, use = SOAPBinding.Use.LITERAL)
public class WebserviceController {

	@Autowired
	@Qualifier("welcomeService")
	private WelcomeService welcomeService;

	/**
	 * Constructor
	 */
	public WebserviceController() {
	}

	/**
	 * @param searchCriteria
	 * @param formBinding
	 * @param request
	 * @return
	 */
	@WebMethod(operationName = "getMessage")
	public String search() {
		return welcomeService.hello("Ashwin").getMessage();

	}

	@WebMethod(operationName = "sayHello")
	public String sayHelloToTheUser(@WebParam(name = "name") String userName) {
		return "Testing: " + " " + userName;
	}

}

Sample WSDL URL’s

http://localhost:8080/testspring-webapp/webservice/OrderProcess?wsdl

http://localhost:8080/testspring-webapp/ws?wsdl

 

And finally one more thing which i haven’t used in example. I have configured HSQLDB to used so that any demo’s need not have an external database but have Inbuilt DB

Here is how you do that

	<!-- H2 Database Console for managing the app's database -->
	<servlet>
		<servlet-name>H2Console</servlet-name>
		<servlet-class>org.h2.server.web.WebServlet</servlet-class>
		<init-param>
			<param-name>-webAllowOthers</param-name>
			<param-value>true</param-value>
		</init-param>
		<load-on-startup>2</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>H2Console</servlet-name>
		<url-pattern>/admin/h2/*</url-pattern>
	</servlet-mapping>

 

If you use http://localhost:8080/appname/admin/h2 you will goto to HSQLDB Admin console

I think i have covered all concepts and code snippets to get you started.

Code has been checked in to

https://linkwithweb.googlecode.com/svn/trunk/SpringTutorials/testspring

 

 

 

Checkout

mvn clean install package

testspring-war ( Webapp code for ear file)  (To be deployed on Jboss

testspring-ejb (Has ejb code)

testspring-ear  — Combining both ejb and war to create ear

———————————————–

testspring-java (Java code used in tomcat)

testspring-webapp ( Web configuration for tomcat)

to test on tomcat follow the below steps

cd testspring-webapp

mvn tomcat:run  and njoy playing with code

Njoy playing with code. Get back to me if you have any questions.

 

 

 

 

 

 

 

 

Struts2 , JSON , JQGrid with annotations

This article explains my hardships which trying to get the example work. It is still not fully working solution but a solution which takes you through steps any new guys goes through while trying to configure struts2 using annotation. With introduction of annotation concept in Java5 , many framework’s tried to exploit it very well to make themselves developer friendly. With respect to Web Framework’s Spring MVC is the leader as well as frontrunner in using this. Struts2 has tried to implement the same concepts but for any new developer it be little hard to get it to work as there are not many working articles over the web. I never suggest using any fremawork tags in building UI elements which these framework’s profess ( It would be difficult to reuse/migrate if at all we have migrate in future). I never support people/framework’s who push UI development in hands of developers rather then to designer’s.

Saying this here is example of a sample struts2 application where i have a html named index.jsp which call a Struts2 Action in back-end to get data and presentation is defined in HTML

First of all i’ll define by build structure and dependencies. As i’m planning to use Maven my build structure is default maven build structure here is my pom.xml

<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.linkwithweb.struts2</groupId>
	<artifactId>Struts2Example</artifactId>
	<packaging>war</packaging>
	<version>1.0</version>
	<name>Struts2Example Maven Webapp</name>
	<url>http://maven.apache.org</url>
	<dependencies>

		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.apache.struts</groupId>
			<artifactId>struts2-core</artifactId>
			<version>2.1.8</version>
		</dependency>

		<dependency>
			<groupId>org.apache.struts</groupId>
			<artifactId>struts2-convention-plugin</artifactId>
			<version>2.1.8</version>
		</dependency>

		<dependency>
			<groupId>org.apache.struts</groupId>
			<artifactId>struts2-json-plugin</artifactId>
			<version>2.1.8</version>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>
	<build>
		<finalName>Struts2Example</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.1</version>
				<configuration>
					<source>1.5</source>
					<target>1.5</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>tomcat-maven-plugin</artifactId>
				<version>1.0</version>
				<configuration></configuration>
			</plugin>

			<plugin>
				<groupId>org.mortbay.jetty</groupId>
				<artifactId>jetty-maven-plugin</artifactId>
				<version>7.1.4.v20100610</version>
				<configuration>
					<webApp>${basedir}/target/medihits-admin</webApp>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

The struts2-convention-plugin-version jar file is needed if your are using annotations.

Struts2 has made life little simple by avoiding all the Configuration files it needed before this version by providing configuration by annotation if we just see our web.xml , it’s pretty straightforward where we configure Struts2 Filter to route all requests to corresponding actions

<!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>Struts 2 Sample Web Application</display-name>

	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/struts/*</url-pattern>
	</filter-mapping>

</web-app>

If you observer web.xml i’m filtering all requests that are starting with /struts/* using struts filter. This is entry point of struts application. Now let me describe how we define an Action in Struts2

package com.linkwithweb.user.action;

import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.ResultPath;

import com.opensymphony.xwork2.ActionSupport;
/**
*Example : http://localhost:8080/struts/User
*/
@Namespace("/struts/User")
@ResultPath(value="/")
public class WelcomeUserAction extends ActionSupport{

	private String username;

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

        // Example URL : http://localhost:8080/struts/User/Welcome
	@Action(value="Welcome", results={
			@Result(name="success",location="pages/welcome_user.jsp")
	})
	public String execute() {

		return SUCCESS;	}
}

Looking at above code by now you might have understood how URL are mapped in Struts2.

Now let me describe my effort to add JSON-Plugin. If you have previously observed my pom i have added JSON plugin depdendency

		<dependency>
			<groupId>org.apache.struts</groupId>
			<artifactId>struts2-json-plugin</artifactId>
			<version>2.1.8</version>
		</dependency>

Here is some background how struts2 works

The Convention plug-in is the one which does everything in the background. The Convention plug-in does the following things.

  • By default the Convention plug-in looks for the action classes inside the following packagesstrut, struts2, action or actions. Here our package name is com.vaannila.action. Any package that matches these names will be considered as the root package for the Convention plug-in.
  • The action class should either implement com.opensymphony.xwork2.Action interface or the name of the action class should end with Action. Here we extend our WelcomeUser class from com.opensymphony.xwork2.ActionSupport which inturn implements com.opensymphony.xwork2.Action.
  • The Convention plug-in uses the action class name to map the action URL. Here our action class name is WelcomeUser and the URL is welcome-user. The plug-in converts the camel case class name to dashes to get the request URL.
  • Now the Convention plug-in knows which Action class to call for a particular request. The next step is to find which result to forward based on the return value of the execute method. By default the Convention plug-in will look for result pages in WEB-INF/contentdirectory.
  • Now the Convention plug-in knows where to look for results, but it doesn’t know which file to display inside the content directory. The Convention plug-in finds this with the help of the result code returned by the Action class. If “success” is returned then the Convention plug-in will look for a file name welcome-user-success.jsp or welcome-user.jsp . It need not be a jsp file it can be even a velocity or freemaker files. If the result value is “input” it will look for a file name welcome-user-input.jsp or welcome-user-input.vm or welcome-user-input.ftl.
Now id we need to define a Action which return’s JSON String, we need to define that action implements json-convention which is defined this way
package com.linkwithweb.ajax.action;

import java.util.ArrayList;
import java.util.List;

import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;

import com.opensymphony.xwork2.ActionSupport;

/**
 * @author Ashwin Kumar
 * 
 */
@Namespace("/struts/Ajax")
@Result(name = "success", type = "json")
@ParentPackage("json-default")
public class AjaxAction extends ActionSupport {

	@Action(
			value = "grid",
				results = { @Result(name = "success", type = "json") })
	public String execute() {
		return "success";
	}
/**
 * To Directly write to response and skip all Struts process flows use the below 2 methofs
 */
/*	public HttpServletResponse getResponse() {
		return ServletActionContext.getResponse();
	}*/

	/**
	 * Rename to execute to override
	 * 
	 * @return
	 * @throws Exception
	 *//*
	public String executeToOverrride() throws Exception {
		PrintWriter printWriter = null;
		getResponse().setContentType("text / xml;charset = UTF-8");
		getResponse().setHeader("Cache - Control", "no - cache");

		StringBuffer sb = new StringBuffer("<movie>");
		// let's say you have A Movie object "movie" that needs to be represented as XML
		try {
			printWriter = getResponse().getWriter();
			sb.append("<director>dir</director>");
			sb.append("<language>lang</language>");
			sb.append("<year>year</year>");
			sb.append("</movie>");
			printWriter.print(sb.toString());
		} catch (IOException e) {
			e.printStackTrace();
			throw e;
		} finally {
			printWriter.close();
			printWriter = null;
		}
		return NONE;
	}*/

	/**
	 * @return
	 */
	public String getPage() {
		return "1";
	}

	public int getTotal() {
		return 2;
	}

	public String getRecords() {
		return "13";
	}

	public List<String> getRows() {
		List<String> arrayList = new ArrayList<String>();
		arrayList.add("{'id':'13','cell':['13','2007-10-06','Client 3','1000.00','0.00','1000.00',null]}");
		arrayList.add("{'id':'12','cell':['12','2007-10-06','Client 2','700.00','140.00','840.00',null]}");
		arrayList.add("{'id':'11','cell':['11','2007-10-06','Client 1','600.00','120.00','720.00',null]}");
		arrayList.add("{'id':'10','cell':['10','2007-10-06','Client 2','100.00','20.00','120.00',null]}");
		arrayList.add("{'id':'9','cell':['9','2007-10-06','Client 1','200.00','40.00','240.00',null]}");
		arrayList.add("{'id':'8','cell':['8','2007-10-06','Client 3','200.00','0.00','200.00',null]}");
		arrayList.add("{'id':'7','cell':['7','2007-10-05','Client 2','120.00','12.00','134.00',null]}");
		arrayList.add("{'id':'6','cell':['6','2007-10-05','Client 1','50.00','10.00','60.00','']}");
		arrayList.add("{'id':'5','cell':['5','2007-10-05','Client 3','100.00','0.00','100.00','no tax at all']}");
		arrayList.add("{'id':'4','cell':['4','2007-10-04','Client 3','150.00','0.00','150.00','no tax']}");
		
		
		return arrayList;
	}
}
If you observe the above code any url request of form /struts/Ajax/grid will come to this Action class and as we defined it follows json-default convention and so this class acts as bean and this java bean is converted to json string in response here is sample response for above class
{"page":"1","records":"13","rows":["{'id':'13','cell':['13','2007-10-06','Client 3','1000.00','0.00','1000.00',null]}","{'id':'12','cell':['12','2007-10-06','Client 2','700.00','140.00','840.00',null]}","{'id':'11','cell':['11','2007-10-06','Client 1','600.00','120.00','720.00',null]}","{'id':'10','cell':['10','2007-10-06','Client 2','100.00','20.00','120.00',null]}","{'id':'9','cell':['9','2007-10-06','Client 1','200.00','40.00','240.00',null]}","{'id':'8','cell':['8','2007-10-06','Client 3','200.00','0.00','200.00',null]}","{'id':'7','cell':['7','2007-10-05','Client 2','120.00','12.00','134.00',null]}","{'id':'6','cell':['6','2007-10-05','Client 1','50.00','10.00','60.00','']}","{'id':'5','cell':['5','2007-10-05','Client 3','100.00','0.00','100.00','no tax at all']}","{'id':'4','cell':['4','2007-10-04','Client 3','150.00','0.00','150.00','no tax']}"],"total":2}
I have integrated JQGrid multiselect functionality in index.jsp. here is sample code which configures jqgrid multiselect
jQuery("#list9").jqGrid({
   	url:'response.jsp?time='+new Date().getTime(),
	datatype: "json",
   	colNames:['Inv No','Date', 'Client', 'Amount','Tax','Total','Notes'],
   	colModel:[
   		{name:'id',index:'id', width:55},
   		{name:'invdate',index:'invdate', width:90},
   		{name:'name',index:'name', width:100},
   		{name:'amount',index:'amount', width:80, align:"right"},
   		{name:'tax',index:'tax', width:80, align:"right"},		
   		{name:'total',index:'total', width:80,align:"right"},		
   		{name:'note',index:'note', width:150, sortable:false}		
   	],
   	rowNum:10,
   	rowList:[10,20,30],
   	pager: '#pager9',
   	sortname: 'id',
	recordpos: 'left',
    viewrecords: true,
    sortorder: "desc",
	multiselect: true,
	caption: "Multi Select Example"
});
jQuery("#list9").jqGrid('navGrid','#pager9',{add:false,del:false,edit:false,position:'right'});
jQuery("#m1").click( function() {
	var s;
	s = jQuery("#list9").jqGrid('getGridParam','selarrrow');
	alert(s);
});
jQuery("#m1s").click( function() {
	jQuery("#list9").jqGrid('setSelection',"13");
});
Here is how index.jsp looks like after running ( you can use mvn -Djetty.port=9090 jetty:run or mvn tomcat:run)
Will make it more professional and fix all issues along with article in coming week. Got to work on something else so leave it here
Code has been checked in to following svn location. https://linkwithweb.googlecode.com/svn/trunk/Struts
So play with this as you want