Archive

Archive for March, 2010

Spring EJB 3 Integration

March 23rd, 2010 2 comments

Integrating Spring with EJB allows Session and Message Driven Beans leverage existing Spring infrastructure easily. In this post, I will show how to access Spring beans from a Message Driven Bean. This post builds on my previous “EJB 3 Message Driven Beans in WebLogic 10.3” post.

Step 1: Add the following Spring jar files to the APP-INFlib folder of the EAR project.

org.springframework.aop-3.0.0.RELEASE.jar
org.springframework.asm-3.0.0.RELEASE.jar
org.springframework.aspects-3.0.0.RELEASE.jar
org.springframework.beans-3.0.0.RELEASE.jar
org.springframework.context.support-3.0.0.RELEASE.jar
org.springframework.context-3.0.0.RELEASE.jar
org.springframework.core-3.0.0.RELEASE.jar
org.springframework.expression-3.0.0.RELEASE.jar
org.springframework.jms-3.0.0.RELEASE.jar
commons-logging.jar
log4j-1.2.14.jar

Step 2: The next step is to create a Spring context file in the EJB project to hold the bean definitions. Here is the application-Context.xml file with a simple Spring bean:

	
	

			
							
			

	           

When deployed, the application-Context file should be at the root of the EJB jar.

Step 3: The next step is to modify the Message Driven Bean to use the messageSuffix Spring bean. Here is the modified MDB:

	public class TestMdb implements MessageListener
	{
		@Autowired
		@Qualifier("messageSuffix")
		private String messageSuffix;
		
		public void onMessage(Message message)
		{
			System.out.println(message + ". " + messageSuffix);
		}
	}

Step 4: To next step is to add SpringBeanAutowiringInterceptor to the MDB. The SpringBeanAutowiringInterceptor is an EJB 3 compliant interceptor that injects Spring beans into @AutoWired annotated fields and methods. Here is the complete MDB:


	package com.inflinx.blog.springmdb;

	import javax.ejb.ActivationConfigProperty;
	import javax.ejb.MessageDriven;
	import javax.interceptor.Interceptors;
	import javax.jms.Message;
	import javax.jms.MessageListener;

	import org.springframework.beans.factory.annotation.Autowired;
	import org.springframework.beans.factory.annotation.Qualifier;
	import org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor;

	@MessageDriven(
			mappedName = "jndi.blogQueue",
			activationConfig = { @ActivationConfigProperty(
					propertyName = "destinationType", propertyValue = "javax.jms.Queue"
			)}
	)
	@Interceptors(SpringBeanAutowiringInterceptor.class)
	public class TestMdb implements MessageListener
	{
		@Autowired
		@Qualifier("messageSuffix")
		private String messageSuffix;

		public void onMessage(Message message)
		{
			System.out.println(message + ". " + messageSuffix);
		}
	}

The SpringBeanAutowiringInterceptor by default looks for a beanRefContext.xml file in the classpath to create an ApplicationContext. Create the beanRefContext.xml file with the following content:


	
	

				 
			 		
		
	

This completes the Spring EJB integration. Deploy the EJB and run the MessageGenerator test class. You should see the message “TextMessage[ID:<655281.1269371402940.0>, null]. Now With Spring!!” in the server console.

Download the source code for this project here.

Categories: How To, Spring Tags:

EJB 3 Message Driven Beans in WebLogic 10.3

March 21st, 2010 2 comments

In this post, I will show how to create and test Message Driven Beans in WebLogic 10.3. Here are the steps:

Step 1: The first step is to create projects to hold Message Driven Beans. Using Eclipse IDE, here are the generated EAR and EJB projects:

MDB Project Layout

MDB Project Layout

EAR is the standard packaging mechanism for Java enterprise applications.

Step 2: The next step is to create the Message Driven Bean. The MDB created in this post will be consuming messages from a Distributed Queue with the JNDI name jndi.blogQueue. Refer to the “Distributed JMS Queue on WebLogic 10” post for details on creating Distributed Queues in WebLogic.

	package com.inflinx.blog.springmdb;

	import javax.ejb.ActivationConfigProperty;
	import javax.ejb.MessageDriven;
	import javax.jms.Message;
	import javax.jms.MessageListener;

	@MessageDriven(
			mappedName = "jndi.blogQueue",
			activationConfig = { @ActivationConfigProperty(
					propertyName = "destinationType", propertyValue = "javax.jms.Queue"
				)}
			)

	public class TestMdb implements MessageListener 
	{
	    public void onMessage(Message message) 
	    {
		System.out.println("Received Message: " + message);
	    }
	}

Step 3: The next step is to package the newly created MDB into an EJB which then gets packaged into a ear file for deployment. During development in Eclipse, simply right click on the mdb-ear and click Run -> Run On Server. This IDE deployment assumes that the Oracle Server Adapter is installed in Eclipse and configured to talk to a WebLogic 10.3 server instance.

Step 4: To make sure that the MDB is deployed properly, let us create a MessageGenerator class that adds a message to the queue:

 
		
	public class MessageGenerator 
	{
		public static void main(String[] args) throws Exception
		{
			Context context = getInitialContext();
			
			ConnectionFactory connectionFactory = (ConnectionFactory)context.lookup("jndi.blogfactory");
			Queue queue = (Queue) context.lookup("jndi.blogQueue");
			Connection connection = connectionFactory.createConnection();
			Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
			
			MessageProducer producer = session.createProducer(queue);
	
			TextMessage message = session.createTextMessage();
			message.setText("Hello World");
			producer.send(message);
			
			connection.close();
		}
		
		private static Context getInitialContext() throws Exception
		{
			Hashtable env = new Hashtable();
			env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
			// TODO: Change the server and port name to suit your environment before running the class
			env.put(Context.PROVIDER_URL, "t3://localhost:9001");
			return new InitialContext(env);
		}
	}

Running the above class will add a new TextMessage to the Queue. Once a new message is available, the TestMDB’s onMessage() method gets invoked and you should see the message “Received Message: TextMessage[ID:, null]” in the WebLogic console logs.

For the above class to run from Eclipse, make sure that you remove “WebLogic System Libraries” and add weblogic.jar to the MessageGenerator “Run Configurations…”.

Message Generator Run Configuration

Message Generator Run Configuration

Otherwise you will end up getting the error:

Exception in thread “main” java.lang.NoClassDefFoundError: weblogic/kernel/KernelStatus
at weblogic.jndi.Environment.(Environment.java:78)
at weblogic.jndi.WLInitialContextFactory.getInitialContext(WLInitialContextFactory.java:117)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
at javax.naming.InitialContext.init(InitialContext.java:223)
at javax.naming.InitialContext.(InitialContext.java:197)
at com.inflinx.blog.test.MessageGenerator.getInitialContext(MessageGenerator.java:40)
at com.inflinx.blog.test.MessageGenerator.main(MessageGenerator.java:18)

 

Download the source code for this post here.

Optional Packages in Weblogic 10.3

March 18th, 2010 3 comments

Optional Packages provide a great way to share individual jar files among multiple applications. Reusable java classes and third party framework classes are good candidates for deploying as optional packages. In this post I will show how to install and use Optional Packages in Weblogic 10.3.

I. Create Jar file
The first step in the process is to bundle a reusable Java class as a Jar file. To keep things simple, I will create a simple String Utility class.

 	
	public class StringUtil
	{
		public static boolean isEmpty(String text)
		{
			return null == text || "".equals(text);
		}
		
	}

The next step is to create a MANIFEST.MF file with the following information:

Manifest-Version: 1.0
Extension-Name: StringLib
Specification-Version: 1.0.0.0
Implementation-Version: 1.0.0.0

As you can see, the MANIFEST.MF file holds the information about the library such as name and version. The next step is to package the application into a jar file.

 

II. Install Optional Packages
Launch WebLogic console and click on Deployments:

Domain Structure

Domain Structure

Click on Install and on the next screen, browse to the folder containing the jar and select the jar:

Select Jar

Select Jar

Select the defaults on the next page and hit Finish. Restart the server for the changes to take effect.

 

III. Using Optional Packages in Web Application
Open the application’s MANIFEST.MF under META-INF folder and add the following entries:

Manifest-Version: 1.0
Extension-List: strlib
strlib-Extension-Name: StringLib
strlib-Specification-Version: 1.0.0.0
strlib-Implementation-Version: 1.0.0.0

Modify application’s code to start using the StringLib library. Even though Optional Packages are not deployed along with the application, you still might need them in your application’s class path during development. Maven users can do this by changing the jar dependency to provided in their pom.xml file.

 

Download stringlib.jar and demo war file along with source code here.

Categories: Solutions Log Tags:

JSR 303 Bean Validation Using Spring 3

March 10th, 2010 27 comments

The JSR 303 specification provides a metadata model for JavaBean validation. The validation API provides a variety of annotations that makes validation easy at any layer. In this post I will demo Spring 3’s support for JSR 303 in the web layer. You can download the code here (eclipse project).

The first part of the post talks about creating a simple bookstore admin application using Spring MVC. The second part of the post will add JSR 303 validation. If you are an experienced Spring developer, you can safely skip to the second part. The final part will show how to customize the validation error messages.

1. Online Bookstore Admin Application

The admin application will be designed to allow administrators enter information about new books. Here are the steps that implement this requirement:

Step 1. Create a web project and add all the required jars
I will be using Eclipse’s and here is a list of the required jars that need to be in the classpath:

org.springframework.asm-3.0.1.RELEASE.jar
org.springframework.beans-3.0.1.RELEASE.jar
org.springframework.context-3.0.1.RELEASE.jar
org.springframework.context.support-3.0.1.RELEASE.jar
org.springframework.core-3.0.1.RELEASE.jar
org.springframework.expression-3.0.1.RELEASE.jar
org.springframework.test-3.0.1.RELEASE.jar
org.springframework.web-3.0.1.RELEASE.jar
org.springframework.web.servlet-3.0.1.RELEASE.jar
commons-collections-3.1.jar
hibernate-validator-4.0.2.GA.jar
jcl-over-slf4j-1.5.10.jar
joda-time-1.6.jar
jstl-1.2.jar
log4j.jar
slf4j-api-1.5.8.jar
slf4j-log4j12.jar
validation-api-1.0.0.GA.jar

Step 2. Create a web-Context.xml file under WEB-INF folder to hold web layer spring bean configuration. Here are the contents of the 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:context="http://www.springframework.org/schema/context"
			xmlns:mvc="http://www.springframework.org/schema/mvc"
			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">
			
			<!-- Enable annotation driven controllers, validation etc... -->
			<mvc:annotation-driven />
			
			<!-- Controllers package -->
			<context:component-scan base-package="com.inflinx.blog.bookstore.web.controller" />
		
			<!-- JSP page location -->
			<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
				<property name="suffix" value=".jsp"/>
			</bean>
			 	
		</beans>
			
	

Step 3. Add Spring MVC Dispatcher Servlet to web.xml file. In the declaration below, Spring MVC will handle all URL requests to html pages.

		
		<?xml version="1.0" encoding="UTF-8"?>
		<web-app version="2.5" 
			xmlns="http://java.sun.com/xml/ns/javaee" 
			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
			xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
			http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
			  
		  <servlet>
				<servlet-name>bookstore</servlet-name>
				<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
				<init-param>
					<param-name>contextConfigLocation</param-name>
					<param-value>/WEB-INF/web-Context.xml</param-value>
				</init-param>
				<load-on-startup>1</load-on-startup>
			</servlet>
		
			<servlet-mapping>
				<servlet-name>bookstore</servlet-name>
				<url-pattern>*.html</url-pattern>
			</servlet-mapping>
		
		</web-app>
		
	

Step 4. Create a Book domain object to hold information about a book:

		package com.inflinx.blog.bookstore.domain;

		public class Book
		{
			private String name;
			private String description;

			public String getName()
			{
				return name;
			}
			public void setName(String name)
			{
				this.name = name;
			}
			public String getDescription()
			{
				return description;
			}
			public void setDescription(String description)
			{
				this.description = description;
			}

			@Override
			public String toString()
			{
				return "Name: " + name + ", Description: " + description ;
			}
		}	
	

Step 5. Create a BookFormController to prepare the form and process form submission

		package com.inflinx.blog.bookstore.web.controller;
		
		import java.util.Map;
		
		import org.springframework.stereotype.Controller;
		import org.springframework.web.bind.annotation.RequestMapping;
		import org.springframework.web.bind.annotation.RequestMethod;
		
		import com.inflinx.blog.bookstore.domain.Book;
		
		@Controller
		@RequestMapping("/book.html")
		public class BookFormController
		{
			// Display the form on the get request
			@RequestMapping(method=RequestMethod.GET)
			public String showForm(Map model)
			{
				Book book  = new Book();
				model.put("book", book);
				return "form";
			}
			
		}
	
	

Step 6. Create form.jsp page with a form to capture book details:

	
		<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
		<html>
			<head></head>
			<body>
				<form:form method="post" action="book.html" commandName="book">
					<table>
						<tr>
							<td>Name:</td> <td><form:input path="name" /></td>
						</tr> 
						<tr>
							<td>Description:</td> <td><form:textarea path="description"/></td>
						</tr>
						</table>
					<input type="submit" value="Create" />
				</form:form>
			</body>
		</html>
	
	
	

The form will be submitted to the book.html page.

Step 7. Modify BookFormController to read the submitted data and process it.

		
		// Process the form. 
		@RequestMapping(method=RequestMethod.POST)
		public String processForm(Book book, Map model)
		{
			// Persistence logic to save the book will go here

			// Add the saved book to the model
			model.put("book", book);
			return "result";
		}	
	

Step 8. Create a result.jsp page to display the form submission result:

		<html>
			<body>
				${book.name} is stored in the database
			</body>
		</html>
	

Deploy the application and go to http://<yourserver:port>/bookstore/book.html. The page should present a form shown below:

Form

Form

Enter the book name “Test Book” and submit the form. You should see a screen that looks similar to image below:

Form Submission Result

Form Submission Result

 

2 Adding JSR 303 validation

Consider the following validation requirements to the book class:
a. Name and Description cannot be null or blank
b. Description cannot be more than 50 characters

Here are the steps to add the above validation requirements:

Step 1. Add @NotEmpty and @Size annotations to the name and description files of the Book class

		public class Book
		{
			@NotEmpty
			private String name;
			
			@Size(min=1, max=50)
			private String description;
			
			// Getters and setters here	
		}
	

NotEmpty annotation is not part of JSR 303 specification. It is part of Hibernate Validator framework which is the reference implementation for JSR 303.

Step 2. Modify BookFormController to have Spring validate the submitted data. This is done by adding a @Valid annotation before the book method parameter. The result of the validation can be accessed using the BindingResult method parameter.

		// Process the form. 
		@RequestMapping(method=RequestMethod.POST)
		public String processForm(@Valid Book book, BindingResult result, Map model)
		{
			if(result.hasErrors())
			{
				return "form";
			}
			// Persistence logic to save the book will go here

			// Add the saved book to the model
			model.put("book", book);
			return "result";
		} 	
 	

Step 3. Modify the form.jsp so that error messages can be displayed:

 		<form:form method="post" action="book.html" commandName="book">
					<table>
						<tr>
							<td>Name:</td> <td><form:input path="name" /></td> <td><form:errors path="name" /></td>
						</tr> 
						<tr>
							<td>Description:</td> <td><form:textarea path="description"/></td> <td><form:errors path="description" /></td>
						</tr>
						</table>
					<input type="submit" value="Create" />
		</form:form>
 	

Redeploy the application and when you submit an empty form, you should see validation failure messages next to the fields:

Validation Failed

Validation Failed

 

3 Customizing error messages

The validation failure messages in the image above are default to the framework. To make custom error messages appear follow these steps:

Step 1. Create a messages.properties file under the WEB-INF folder. Add the following messages:

   		NotEmpty.book.name=Name is a required field
		Size.book.description=Description must be between 1 and 50 characters
   	

Each message above follows this convention:

<CONSTRAINT_NAME>.<COMMAND_NAME>.<FIELD_NAME>

Step 2. Let Spring know about the newly created properties file. This is done by modifying the web-Context.xml file to include this bean declaration:

   	
			
	
    

Redeploy the application and submit an empty form. This time you should see custom error messages appear next to the fields:

Custom Validation Failed Messages

Custom Validation Failed Messages

 

Download the source code for this post here. The application is tested on Glassfish 3.0 and WebLogic 10.3.