Archive

Archive for the ‘Solutions Log’ Category

JSR 303 Bean Validation Using Spring 3

March 10th, 2010

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: ..

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.

 

Balaji Solutions Log, Spring , ,

weblogic.xml deployment descriptor

December 31st, 2009

If you are using 10.3.0 version of Weblogic here is a sample weblogic.xml file with correct schema information:





	YOUR_APPLICATION_CONTEXT_NAME


And here is a sample weblogic.xml file for version 10.3.2 version:





     	YOUR_APPLICATION_CONTEXT_NAME


If you use the wrong version file, you might end up with exceptions like this:

com.bea.xml.XmlException: failed to load java type corresponding to e=weblogic-web-app@http://xmlns.oracle.com/weblogic/weblogic-web-app
at com.bea.staxb.runtime.internal.UnmarshalResult.getPojoBindingType(UnmarshalResult.java:361)
at com.bea.staxb.runtime.internal.UnmarshalResult.determineTypeForGlobalElement(UnmarshalResult.java:316)
at com.bea.staxb.runtime.internal.UnmarshalResult.determineTypeForGlobalElement(UnmarshalResult.java:326)
at com.bea.staxb.runtime.internal.UnmarshalResult.determineRootType(UnmarshalResult.java:307)
at com.bea.staxb.runtime.internal.UnmarshalResult.unmarshalDocument(UnmarshalResult.java:158)
Truncated. see log file for complete stacktrace

Balaji Solutions Log

Redirecting from Wordpress.com

October 14th, 2009

The blog post WordPress.com to Wordpress.org is an excellent reference if you are planning on redirecting your existing Wordpress.com blog to a blog on a domain you own. However, it does not talk about redirecting a Wordpress.com blog to a blog on a sub-domain. In this post, I want to share the steps I followed to redirect my http://onerandomthought.wordpress.com blog to http://blog.inflinx.com hosted on Go Daddy. I am assuming that you have already moved all your posts from your Wordpress.com blog to your new blog and verified that Permalinks on both blogs match.

 

Step 1: Log into http://wordpress.com and go to the Domains in the Dashboard. Under “Add a Domain” enter your subdomain.domain.com and hit “Add domain to blog”:
 Add a Domain

 

Wordpress would come back complaining that there is a possible problem with the domain, It recommends that we add a CNAME entry pointing to Wordpress.com blog in registrar before proceeding:
Problem Adding Domain

 

Step 2: Log into your godaddy.com account and launch Domain Manager. Select the domain name in the list of domains:
Go Daddy Select Domain

 

On the resulting page, click on the “Total DNS Control”:
Total DNS Selection

 

Inside the “Total DNS Control”, before I could add a CNAME entry for “blog”, I had to delete the existing “blog” record under A (HOST). The delete option is listed under “Actions”. Make sure you save the IP address that blog is pointing to:
 Delete Sub Domain

 

The next step is to create a new CNAME entry. Click on the Add New CNAME Record and fill the resulting form. Then, hit Ok and it would create a new CNAME record:
Add CNAME Record

 

Step 3: Repeat Step 1 and now wordpress.com should allow you to register the domain:
Wordpress - Add a sub domain

 

Follow the next steps and purchase the credits to register the domain:
Purchase Domain Mapping

 

Once the purchase, is complete, All the traffic for blog.inflinx.com should now be redirected to onerandomthought.wordpress.com.
After Domain Mapping Purchase
You might need to clear the DNS Cache to verify the redirect. On Max OSX, this is done through the command: dscacheutil -flushcache

 

Step 4: Now that we have this going, we just need to reverse the redirection behavior. In the Wordpress.com, select the radio button next to your sub domain and hit “Update Primary Domain”. Then, go back to the “Total DNS Control” and undo what was done in Step 2. This involves first deleting the CNAME entry and adding the blog entry under A(Host). Make sure you are using the same IP address you saved in step 2.

 

Once Step 4 is completed, all the Wordpress.com blog traffic should now be sent over to the blog on your sub domain.

Balaji Solutions Log, Wordpress

Adding JQuery Slider Part II

October 9th, 2009

In my last post I showed how to easily add slider functionality using JQuery. In this post I will showcase some of the options that slider provides with a Temperature Converter. This is how it will work: the slider represents temperature measured in Celsius units and ranges between 0 and 100. As the user drags the slider, we will display the temperature equivalent in Fahrenheit.

Lets start by registering a basic slider:

   <script type="text/javascript">
	$(function()
	{
		$("#slider").slider();
	});
   </script>

Since the slider converts temperatures in the range 0 celsius and 100 celsius, modify the slider definition to include the range:

	$("#slider").slider({
		min: 0,
		max: 100,
		step: 1

	});

The next step is to add two span tags to display the chosen temperature and the temperature in Fahrenheit:

	Temperature in Celsius: <span id="celsius">0</span>
	
	Temperature in Fahrenheit: <span id="fahrenheit"></span>

Finally all we need to do would be to captrue the slide event so that we can update the span tags:

	$("#slider").slider({
		min: 0,
		max: 100,
		step: 1,
		slide: handleSlide
	});

The handleSlide is a javascript function that looks like this:

	function handleSlide(event, ui)
	{
		// Update the celsius span
		$("#celsius").html(ui.value);

		// Compute the fahrenheit equivalent
		var fTemp = (1.8 * ui.value) + 32;

		// Just display the last two digits of the temp
		$("#fahrenheit").html(fTemp.toFixed(2));
	}

Here is a working demo

Balaji JQuery, Solutions Log

Adding JQuery UI Slider

October 1st, 2009

Here are five easy steps to add slider functionality to your web applications:

Step 1: Go to JQuery UI site and create a custom download. To keep things simple, select “No Theme”.under theme section and deselect all but UI Core and Slider checkboxes. Hit Download and unzip the downloaded file.

Step 2: Copy the jquery-1.3.2.min.js and “jquery-ui-1.7.2.custom.min.js” files into your project. These files should be under the js folder. Include the js files in your html/jsp page.

	
	
      

Step 3: Add the following styles to the page:


I am using the slider bar and slider handle images from YUI

Step 4: Add a DIV for the slider in the HTML.

Step 5: Initialize the slider in the document ready function:

	
      

That’s it. You can find a demo of this example here.

Balaji Getting Started, JQuery, Solutions Log , ,

Mousefeed Eclipse Plugin

July 30th, 2009

Today, I ran into a really cool eclipse plugin called Mousefeed. Once installed, this plugin will popup a reminder with shortcut information every time a button or a menu item is clicked using mouse.

I find this a great way to quickly learn Eclipse shortcuts and becoming productive with the IDE.

Balaji Solutions Log

Changing Maven4MyEclipse Web Project Directory Structure

September 11th, 2008

When you create a MyEclipse Web Project with Maven capabilities, the generated directory structure does not match the “standard” Maven Web Project structure. I find this little annoying and here is what I did to change the directory structure:

  • Under “src” folder, create two folders main and test. Underneath each folder create two folders java and resources
  • Go to project properties and under Java Build Path, first remove “src” folder from being a source folder. Make java and resources folders source folders
  • Create webapp folder underneath src/main. Create WEB-INF and classes folders under webapp. Move the web.xml under WebRoot/WEB-INF to webapp/WEB-INF folder
  • In the .mymetadata file located in the project root folder (use Navigator view to get to the file in MyEclipse), change the attribute webrootdir’s value to /src/main/webapp
  • In the .classpath file, change the classpathentry of kind “output” from “WebRoot/WEB-INF/classes” to “src/main/webapp/WEB-INF/classes”
  • Delete the WebRoot directory and restart MyEclipse

The original pom.xml generated as part of the Maven4MyEclipse Web Project has several entries (sourcedirectory, resource directory e.t.c.) to reflect MyEclipse Web project directory structure. These entries can be safely deleted. Once this is done, the new project can be used to hot-deploy the war file. And yes, dependencies declared as “test” will not end up in the lib directory of the hot-deployed war file.

Balaji Maven, Maven4MyEclipse, MyEclipse, Solutions Log