Archive

Archive for October, 2012

Spring MVC – Sitemesh 3 Integration

October 9th, 2012 4 comments

Sitemesh is a web page layout/decoration framework that makes it easy to create applications with consistent layout/look and feel. I have used Sitemesh 2 for years and absolutely love it. Sitemesh 3 is a complete rewrite of the framework and has huge performance benefits. A full list of the new features is listed here. In this blog I will share the steps needed for integrating Sitemesh 3 in a Spring MVC application.

1. We start by creating a Maven based web application using my Spring archetype. Here is the generated pom.xml file with dependencies:


<?xml version="1.0" encoding="UTF-8"?>
<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.inflinx.blog</groupId>
	<artifactId>sitemesh3</artifactId>
	<name>sitemesh3</name>
	<packaging>war</packaging>
	<version>1.0.0</version>
	
	<properties>
		<org.springframework-version>3.1.1.RELEASE</org.springframework-version>
	</properties>
	
	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework-version}</version>
			 <exclusions>
		         <exclusion>
		            <groupId>commons-logging</groupId>
		            <artifactId>commons-logging</artifactId>
		         </exclusion>
      		</exclusions>
		</dependency>
		
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		
		<dependency>
		     <groupId>cglib</groupId>
		     <artifactId>cglib</artifactId>
		     <version>2.2.2</version>
		     <scope>compile</scope>
		</dependency>
		
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>
		
		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			<version>1.0.0.GA</version>
			<scope>compile</scope>
		</dependency>
		
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>4.2.0.Final</version>
			<scope>compile</scope>
			<exclusions>
				<exclusion>
					<artifactId>slf4j-api</artifactId>
					<groupId>org.slf4j</groupId>
				</exclusion>
			</exclusions>
		</dependency>
	            
		<dependency>
			<groupId>jstl</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
	
		<dependency>
      		<groupId>org.slf4j</groupId>
	      	<artifactId>jcl-over-slf4j</artifactId>
	      	<version>1.5.8</version>
  	 	</dependency>
   		<dependency>
      		<groupId>org.slf4j</groupId>
      		<artifactId>slf4j-api</artifactId>
      		<version>1.5.8</version>
   		</dependency>
	   <dependency>
	      <groupId>org.slf4j</groupId>
	      <artifactId>slf4j-log4j12</artifactId>
	      <version>1.5.8</version>
	   </dependency>
	
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.14</version>
		</dependency>
			  
		<dependency>
			<groupId>commons-lang</groupId>
			<artifactId>commons-lang</artifactId>
			<version>2.6</version>
		</dependency>            
		
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.0</version>
	    	<scope>provided</scope>
		</dependency>				
 
	</dependencies>
    <build>
        <plugins>
        	<plugin>
			    <groupId>org.mortbay.jetty</groupId>
			    <artifactId>maven-jetty-plugin</artifactId>
			</plugin>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <additionalProjectnatures>
                        <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                    </additionalProjectnatures>
                    <additionalBuildcommands>
                        <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                    </additionalBuildcommands>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>


2. To the web application we add the following Sitemesh 3 maven dependency:

	
		<dependency>
			<groupId>org.sitemesh</groupId>
			<artifactId>sitemesh</artifactId>
			<version>3.0-alpha-2</version>	
		</dependency>
	
	

3. We then create a Sitemesh decorator containing common layout/look and feel that all the pages should have. Create a main.jsp file under WEB-INF/decorator folder with the following contents:


<html>
  <head>
    <title><sitemesh:write property='title'/></title>
    <sitemesh:write property='head'/>
  </head>
  
  <body>
    <div style="color: red">
    	<sitemesh:write property='body'/>
    </div>
  </body>
  
</html> 

4. The next step is to let Sitemesh know about this decorator. This is done via sitemesh.xml file located under WEB-INF folder.

	<?xml version="1.0" encoding="UTF-8"?>
	<sitemesh>
 		<mapping path="/*" decorator="/WEB-INF/decorator/main.jsp"/>
	</sitemesh>

In the above configuration file, the mapping element tells Sitemesh to apply main.jsp decorator to all the pages. Other configuration options provided by Sitemesh 3 are listed here.

5. The final step in the integration is to add Sitemesh filter to web.xml.

  	<filter>
    	<filter-name>sitemesh</filter-name>
    	<filter-class>org.sitemesh.config.ConfigurableSiteMeshFilter</filter-class>
  	</filter>

 	<filter-mapping>
    	<filter-name>sitemesh</filter-name>
    	<url-pattern>/*</url-pattern>
  	</filter-mapping>

When you run the application you should see the red font color applied due to main.jsp decorator:

Sitemesh App

Categories: SiteMesh, Spring Tags: ,

10 Minute Guide to Spring Web Services

October 5th, 2012 1 comment

Spring Web Services simplifies creation of contract-first SOAP based web services. In this blog post, I will create a hello world web service using Spring Web Services. The service will take a string as a parameter, prepends “Hello ” and returns it. Here are the steps for creating the service:

1. We start by creating a maven based web project. Spring Web Services provides an archetype that can be used to simplify creation of web service project.

2. Add Spring Web Services and its dependent jars to the project. Here is the maven dependency that you need to add:

	
	 <dependencies>
        <dependency>
            <groupId>org.springframework.ws</groupId>
            <artifactId>spring-ws-core</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>
    </dependencies>
	
	

3. Since we are developing contract first web service, we create a data contract that defines the input and output messages the service accepts. Create a helloworld.xsd file under WEB-INF folder with the following content:

	
	<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="qualified"
        targetNamespace="http://blog.inflinx.com/ws/helloworld"
        xmlns:tns="http://blog.inflinx.com/ws/helloworld">

     <element name="helloworldRequest" type="string"/>

    <element name="helloworldResponse" type="string"/>
</schema>
	
	

4. The next step is to create an Endpoint that handles incoming XML messages. Here is the HelloWorldEndpoint implementing hello world service:

package com.inflinx.blog.helloworld;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

@Endpoint
public class HelloWorldEndpoint {
	
	 private static final String NAMESPACE_URI = "http://blog.inflinx.com/ws/helloworld";
	
	 private static final String REQUEST_LOCAL_NAME = "helloworldRequest";
	 
	 private static final String RESPONSE_LOCAL_NAME = "helloworldResponse";
	 
	 
	 @PayloadRoot(localPart = REQUEST_LOCAL_NAME, namespace = NAMESPACE_URI)
	 @ResponsePayload
	 public Element handleRequest(@RequestPayload Element requestElement) throws Exception {
		 
		 // Get the submitted text value
		 String text = requestElement.getChildNodes().item(0).getNodeValue();
		 
		 System.out.println("Request Pay Load: " + text);
		 
		 // Create a response Element
		 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
		 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
	     Document document = documentBuilder.newDocument();
	     Element responseElement = document.createElementNS(NAMESPACE_URI, RESPONSE_LOCAL_NAME);
	     Text responseText = document.createTextNode("Hello "+ text);
	     responseElement.appendChild(responseText);
		 
		 return responseElement;
	 }
}

As you can see, the class is annotated with @EndPoint enabling it for component scanning. The @PayloadRoot annotation tells Spring that handleRequest method can handle XML messages. The method implementation is self explanatory: we get the submitted text, create a new response element and return the text with Hello prepended.

5. The next step is to add a Spring Web Service MessageDispatcherServlet to web.xml and map all the incoming requests to it. Here is the modified web.xml file:


<?xml version="1.0" encoding="UTF-8"?>
<web-app 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"
         version="2.4">

    <display-name>Hello World Web Service</display-name>

    <servlet>
        <servlet-name>spring-ws</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>spring-ws</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>

6. The MessageDispatcherServlet is named spring-ws. Hence the servlet will look for a Spring configuration file named spring-ws-servlet.xml under WEB-INF folder. Here is the spring-ws-servlet.xml file:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:sws="http://www.springframework.org/schema/web-services"
       xmlns:context="http://www.springframework.org/schema/context"
       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="com.inflinx.blog.helloworld"/>
	
    <sws:annotation-driven/>

	 <sws:dynamic-wsdl id="helloworld" portTypeName="helloworld" locationUri="http://localhost:8080/hello-world">
        <sws:xsd location="/WEB-INF/helloworld.xsd"/>
    </sws:dynamic-wsdl>

</beans>

The dynamic-wsdl element generates a WSDL automatically for the web service.

7. Deploy the application to a container such as Tomcat or Glassfish. Once deployed, the WSDL can be accessed using the URL: http://localhost:8080/helloworld/helloworld.wsdl

8. Finally, using SOAP UI submit the following request:


<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:hel="http://blog.inflinx.com/ws/helloworld">
   <soapenv:Header/>
   <soapenv:Body>
      <hel:helloworldRequest>World</hel:helloworldRequest>
   </soapenv:Body>
</soapenv:Envelope>

You should see the following response from the service:


<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <SOAP-ENV:Body>
      <helloworldResponse xmlns="http://blog.inflinx.com/ws/helloworld">Hello World</helloworldResponse>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>