Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Wednesday, July 2, 2014

SpringBoot: Introducing SpringBoot

SpringBoot...there is a lot of buzz about SpringBoot nowadays. So what is SpringBoot?

SpringBoot is a new spring portfolio project which takes opinionated view of building production-ready Spring applications by drastically reducing the amount of configuration required. Spring Boot is taking the convention over configuration style to the next level by registering the default configurations automatically based on the classpath libraries available at runtime.
Well.. you might have already read this kind of introduction to SpringBoot on many blogs. So let me elaborate on what SpringBoot is and how it helps developing Spring applications more quickly.

Spring framework was created by Rod Johnson when many of the Java developers are struggling with EJB 1.x/2.x for building enterprise applications. Spring framework makes developing the business components easy by using Dependency Injection and Aspect Oriented Programming concepts. Spring became very popular and many more Spring modules like SpringSecurity, Spring Batch, Spring Data etc become part of Spring portfolio. As more and more features added to Spring, configuring all the spring modules and their dependencies become a tedious task. Adding to that Spring provides atleast 3 ways of doing anything :-). Some people see it as flexibility and some others see it as confusing.

Slowly, configuring all the Spring modules to work together became a big challenge. Spring team came up with many approaches to reduce the amount of configuration needed by introducing Spring XML DSLs, Annotations and JavaConfig.

In the very beginning I remember configuring a big pile of jar version declarations in <properties> section and lot of <dependency> declarations. Then I learned creating maven archetypes with basic structure and minimum required configurations. This reduced lot of repetitive work, but not eliminated completely. 

Whether you write the configuration by hand or generate by some automated ways, if there is code that you can see then you have to maintain it.

So whether you use XML or Annotations or JavaConfig, you still need to configure(copy-paste) the same infrastructure setup one more time.

On the other hand, J2EE (which is dead long time ago) emerged as JavaEE and since JavaEE6 it became easy (compared to J2EE and JavaEE5) to develop enterprise applications using JavaEE platform.
Also JavaEE7 released with all the cool CDI, WebSockets, Batch, JSON support etc things became even more simple and powerful as well. With JavaEE you don't need so much XML configuration and your war file size will be in KBs (really??? for non-helloworld/non-stageshow apps also :-)).
Naturally this "convention over configuration" and "you no need to glue APIs together yourself, JavaEE appServer already did it" arguments became the main selling points for JavaEE over Spring. Then Spring team addresses this problem with SpringBoot :-).
Now its time to JavaEE to show whats the SpringBoot's counterpart in JavaEE land :-) JBoss Forge?? I love this Spring vs JavaEE thing which leads to the birth of powerful tools which ultimately simplify the developers life :-).

Many times we need similar kind of infrastructure setup using same libraries. For example, take a web application where you map DispatcherServlet url-pattern to "/", implement RESTFul webservices using Jackson JSON library with Spring Data JPA backend. Similarly there could be batch or spring integration applications which needs similar infrastructure configuration.

SpringBoot to the rescue. SpringBoot look at the jar files available to the runtime classpath and register the beans for you with sensible defaults which can be overridden with explicit settings. Also SpringBoot configure those beans only when the jars files available and you haven't define any such type of bean. Altogether SpringBoot provides common infrastructure without requiring any explicit configuration but lets the developer overrides if needed.

To make things more simpler, SpringBoot team provides many starter projects which are pre-configured with commonly used dependencies. For example Spring Data JPA starter project comes with JPA 2.x with Hibernate implementation along with Spring Data JPA infrastructure setup. Spring Web starter comes with Spring WebMVC, Embedded Tomcat, Jackson JSON, Logback setup.

Aaah..enough theory..lets jump onto coding.

I am using latest STS-3.5.1 IDE which provides many more starter project options like Facebbok, Twitter, Solr etc than its earlier version.

Create a SpringBoot starter project by going to File -> New -> Spring Starter Project -> select Web and Actuator and provide the other required details and Finish.


This will create a Spring Starter Web project with the following pom.xml and Application.java

<?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/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>

 <groupId>com.sivalabs</groupId>
 <artifactId>hello-springboot</artifactId>
 <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

 <name>hello-springboot</name>
 <description>Spring Boot Hello World</description>

 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.1.3.RELEASE</version>
  <relativePath/>
 </parent>

 <dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-actuator</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
  </dependency>  
 </dependencies>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <start-class>com.sivalabs.springboot.Application</start-class>
  <java.version>1.7</java.version>
 </properties>

 <build>
  <plugins>
   <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
   </plugin>
  </plugins>
 </build>

</project>
package com.sivalabs.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
Go ahead and run this class as a standalone Java class. It will start the embedded Tomcat server on 8080 port. But we haven't added any endpoints to access, lets go ahead and add a simple REST endpoint.
@Configuration
@ComponentScan
@EnableAutoConfiguration
@Controller
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    } 
 
 @RequestMapping(value="/")
 @ResponseBody
 public String bootup()
 {
  return "SpringBoot is up and running";
 }
}

Now point your browser to http://localhost:8080/ and you should see the response "SpringBoot is up and running".

Remember while creating project we have added Actuator starter module also. With Actuator you can obtain many interesting facts about your application. 

Try accessing the following URLs and you can see lot of runtime environment configurations that are provided by SpringBoot. 


SpringBoot actuator deserves a dedicated blog post to cover its vast number of features, I will cover it in my upcoming posts. 

I hope this article provides some basic introduction to SpringBoot and how it simplifies the Spring application development. More on SpringBoot in upcoming articles.

Sunday, December 29, 2013

Clean Code: Don't mix different levels of abstractions

We spend more time on reading code than writing. So if the code is more readable then obviously it will increase the developer productivity.

Many people associate readability of code with coding conventions like following standard naming conventions, closing file, DB resources etc etc. When it comes to code reviews most of the people focus on these trivial things only, like checking for naming convention violations, properly releasing resources in finally block or not.

Do we need "Senior Resources" in team (I hate to call a human being as a Resource) to do these things?Tools like Findbugs, PMD, Checkstyle, Sonar can do that for you. I agree that following a standard naming convention by all the team members is a good thing. But that doesn't increase the readability of code.

Let us take a simple example. I would like to implement Fund Transfer usecase and following are the rules to implement:

  • Source and target accounts should be valid accounts
  • Check whether source account has sufficient amount
  • Check whether source account has provision for Overdraft and check whether this transaction exceeds the overdraft limit
  • Check for duplicate transaction with last transaction. If source, target accounts and amount is same with last transaction consider it as a duplicate transaction
  • If everything is fine then transfer amount to target account

Assume we have the following implementation for the above usecase:



The above code is readable..right??...because:
1. We have followed naming conventions like camel casing variable names
2. We have all the open braces ({) on the method definition line
3. We have closed DB Connection in finally block
4. we have logged exception instead of using System.err.println()
 and most important, it is working as expected.

So is it readable and clean code?? In my opinion absolutely not. There are many issues in the above code from readability perspective.
1. Mixing DB interaction code with business logic
2. Throwing IllegalArgumentException, RuntimeException etc from business methods instead of Business specific exceptions
3. Most importantly, the code is mixed with different levels of abstractions.

Let me explain what I mean by different levels of abstractions.

Firstly, from business perspective fund transfer means validating source/target accounts, checking for sufficient balance, checking for overdraft limit, checking for duplicate transaction and making the fund transfer.

From technical point of view there are various tasks like fetching Account details from DB, performing all the business related checks, throwing Exceptions if there are any violations, properly closing the resources etc.

But in the above code everything is mixed together.

While reading the code you start looking at JDBC code and your brain is working in Technical mode and after getting Account object from ResultSet you are checking for null and throwing Exception if it is null which is Business requirement. So immediately you need to switch your mind to Business mode and think "OK, if the account is invalid we want to abort the operation immediately".

Though you managed to switch between Technical and Business modes, what about making an enhancement to one perticular subtask like "Fund transfer is considred duplicate only if it matches with the last transaction that happened with in an hour only". To make that enhancement you have to go through the entire method because you haven't modularised your sub-tasks and there is no separation of concerns.

Lets rewrite the above method as follows:



The above improved method do exactly what the initial verson is doing but now it looks lot better than earlier version.


  • We have divided the entire task into sub-tasks and implemented each sub-task in a separate method.
  • We have delegated DB interactions to DAOs
  • We are throwing Business specific Exceptions instead of Java language Exceptions
  • All in all we have separated the levels of abstractions.


At the first level we have highest level of abstraction in transferFunds(FundTransferTxn txn) method. By looking at this method we can understand what we are doing as part of Fund Transfer operation without worrying much about implementation or technical details.

At the second level we have business logic implementation methods checkForOverdraft, checkForDuplicateTransaction etc which performs business logic, again without worrying much about technical details.

At the lowest level we have technical implementation details in AccountDAO and TransactionDAO which contains DB interaction logic.

So the reader(future developer/maintainer) of your code can easily understand what you are doing at the high level and can dig into method which he is interested in.

As I said earlier, if we have to make the change to consider the transaction as a duplicate transaction only if it happened with in an hour, we can easily understand that checkForDuplicateTransaction() is the one we have to look into and make change.

Happy coding!!

Monday, October 21, 2013

Drools JBoss Rules 5.X Developer’s Guide Book Review


We all start our new projects by promising to follow best practices and good design principles etc.
But over the time business rules change and developers keep adding new features or updates existing logic.
In this process the common mistake done by many teams is putting if-else conditions here and there instead of coming up with better design to support enhancements. Once these feature turn on/off flags and behavior branching logic started creeping into code then overtime it might become un-maintainable mess. The original developers who design the basic infrastructure might left the organization and the current team left with a huge codebase with if-else/switch conditions all over the code.

So we should be very careful while designing the classes holding the business rules and should be flexible for changes. No matter how much care you take you might still need to touch the code whenever a business rule changes.

This is a problem because we are burying the business logic in the code. Drools framework tries to address this problem by externalizing the business rules which can be authored or updated by non-technical people as also (at least theoretically :-)).

Recently a new book is published by Packt Publishing titled "Drools JBoss Rules 5.X Developer’s Guide".

Drools JBoss Rules 5.X Developer’s Guide http://www.packtpub.com/jboss-rules-5-x-developers-guide/book

I was asked to review the book and here it goes.

Chapter 1: Programming declaratively
I would strongly suggest to read this chapter even if you are already familiar with Drools.
Author Michal Bali explained the problems with putting business rules in code and how Drools addresses these problems.
This chapter also has When not to use Drools section which I find very useful to determine whether you really need Drools for your project or is it overkill.

Chapter 2: Writing Basic Rules:
Here you can start getting your hands dirty by familiarizing yourself with Drools syntax and trying out simple examples.
This chapter also introduces various concepts and terminology of Drools, so don't skip this.

Chapter 3: Validating
This chapter covers building a decision service for validating domain model. Any concepts can be explained better with an example rather than lengthy explanations.
Here author did a good job of taking a real world (if not completely real world, but non-trivial) banking domain model and explained how to build the validation rules with several examples.
In this chapter you can find plenty of example code snippets that are commonly used in many of the projects.

Chapter 4: Transforming Data
This chapter covers transforming data from legacy system to new systems and applying various rules in the transformation process.
Author explained how to use IBatis for loading data which I find as outdated topic, now it is MyBatis with cool new features.
Note:
But actually I doubt if any legacy system with huge volumes of data can really use this feature at all because if needs all the data to be loaded in memory.
I prefer Kettle(Pentaho Data Integration) kind of tools for this purpose.

Chapter 5: Creating Human-readable Rules
One of the main promises of Drools is you can configure business rules in human readable format.
Ofcourse developers are also human beings(:-)) but here the meaning is non-technical people also should be able to understand the rules and with little bit of training they should be able to configure new rules or update existing ones. This chapter covers authoring the rules using Domain Specific Language (DSL). Author covered wide variety of rules configuration options using DSL including configuring and uploading rules  from CSV or XLS files.

The rest of the chapter go in-depth of Drools covering advanced topics which I haven't yet gone through.

Chapter 6: Working with Stateful Session
Chapter 7: Complex Event Processing
Chapter 8: Defining Processes with jBPM
Chapter 9: Building a Sample Application
Chapter 10: Testing
Chapter 11: Integrating
Chapter 12: Learning about Performance

Appendix A: Setting Up the Development Environment
Appendix B: Creating Custom Operators
Appendix C: Dependencies of Sample Application

So far I feel it is good read and I would strongly suggest to read this book if you are building an application with complex business rules.

Monday, March 18, 2013

Dear NetBeansIDE, You are just one step away from massive adoption


Well, NetBeansIDE 7.3 is out with plenty of new features, tremendous performance improvements.
In addition to the great support for Java/JavaEE technologies, NetBeansIDE 7.3 comes with decent support for HTML5, Groovy, PHP, C++ as well. If you are skeptic with older versions of NetBeans like 5.x and never again look at NetBeansIDE, I would strongly suggest you to take a look at latest NeaBeans releases specifically 6.9.x on wards.

However, I wish NetBeans should have following features which greatly increases its adoption:
1. NetBeansIDE as a zipped bundle: 
You may ask how does it matters?!!. Think about the enthusiastic developers in so called Big MNCs without having Admin privileges to install any new software.

If the company is using other IDEs and the developer wants to show to his team mates how NetBeans is better than the existing IDE, he can't because he himself can't install NetBeans on his machine. If the developer rise a ticket to install NetBeans 7.3 then he may also have to give a reason why he need that software. If he give reason as "I want to show how NetBeansIDE is better than our current IDE and motivate the team to move to NetBeans" then chances for rejecting the ticket is High :-)

So IMHO, being able to download, extract and use will definitely increase its adoption.

PS: We can get NetBeansIDE as OS Independent Zip. Plz see the comments.

2. Support for latest Application Server Adapters: 
When I first realized that NetBeans 7.x also doesn't have support for JBoss AS 6/7 I was really surprised. And when I heard that NetBeansIDE 7.3 comes with JBoss AS support I was very happy and wanted to hookup my JBossAS7 with NetBeansIDE 7.3. But when I came to know that NetBeans 7.3 supports JBoss 5.x only for now, I was really surprised why NB team spent time on providing support for older JBoss version.

After expressing this concern on Twitter(@sivalabs), Geertjan Wielenga (@geertjanw) replied to my tweet saying support for JBoss AS7 is on the way and probabily comes in-built with next release of NetBeans.

3. More plugins support: 
Lets be honest and say Eclipse has rich plugin support compared to NetBeans. Of course you can say quantity is not matter, quality matters and its true :-)

Sometimes I do weird things like creating a JavaEE project, generating Entities from Database Tables, creating REST Endpoints in NetBeans and import the code into Eclipse and work with it. I do like this because GOD knows when Eclipse's JBoss Tool plugin works properly :-) Anyway, NetBeans needs more plugins support.

Sunday, October 21, 2012

MyBatis Tutorial: Part1 - CRUD Operations

MyBatis is an SQL Mapper tool which greatly simplifies the database programing when compared to using JDBC directly.



MyBatis Tutorial: Part1 - CRUD Operations
MyBatis Tutorial: Part-2: CRUD operations Using Annotations
MyBatis Tutorial: Part 3 - Mapping Relationships
MyBatis Tutorial : Part4 - Spring Integration

Step1: Create a Maven project and configure MyBatis dependencies.

<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/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>

 <groupId>com.sivalabs</groupId>
 <artifactId>mybatis-demo</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>

 <name>mybatis-demo</name>
 <url>http://maven.apache.org</url>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <build>
  <plugins>
   <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>
     <encoding>${project.build.sourceEncoding}</encoding>
    </configuration>
   </plugin>
  </plugins>
 </build>

 <dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.10</version>
   <scope>test</scope>
  </dependency>
  
  <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.1.1</version>
  </dependency>
  <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <version>5.1.21</version>
             <scope>runtime</scope>
         </dependency>
 </dependencies>
</project> 

Step#2: Create the table USER and a Java domain Object User as follows:

CREATE TABLE  user (
  user_id int(10) unsigned NOT NULL auto_increment,
  email_id varchar(45) NOT NULL,
  password varchar(45) NOT NULL,
  first_name varchar(45) NOT NULL,
  last_name varchar(45) default NULL,
  PRIMARY KEY  (user_id),
  UNIQUE KEY Index_2_email_uniq (email_id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


package com.sivalabs.mybatisdemo.domain;
public class User 
{
 private Integer userId;
 private String emailId;
 private String password;
 private String firstName;
 private String lastName;
 
 @Override
 public String toString() {
  return "User [userId=" + userId + ", emailId=" + emailId
    + ", password=" + password + ", firstName=" + firstName
    + ", lastName=" + lastName + "]";
 }
 //setters and getters 
}


Step#3: Create MyBatis configuration files.

a) Create jdbc.properties file in src/main/resources folder 

  jdbc.driverClassName=com.mysql.jdbc.Driver
  jdbc.url=jdbc:mysql://localhost:3306/mybatis-demo
  jdbc.username=root
  jdbc.password=admin
 
b) Create mybatis-config.xml file in src/main/resources folder
 
  <?xml version="1.0" encoding="UTF-8" ?>
  <!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
  <configuration>
   <properties resource="jdbc.properties"/>
   <typeAliases>
    <typeAlias type="com.sivalabs.mybatisdemo.domain.User" alias="User"></typeAlias>
   </typeAliases>
   <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">    
     <property name="driver" value="${jdbc.driverClassName}"/>
     <property name="url" value="${jdbc.url}"/>
     <property name="username" value="${jdbc.username}"/>
     <property name="password" value="${jdbc.password}"/>
      </dataSource>
    </environment>
    </environments>
    <mappers>
   <mapper resource="com/sivalabs/mybatisdemo/mappers/UserMapper.xml"/>
    </mappers>
  </configuration>
 

Step#4: Create an interface UserMapper.java in src/main/java folder in com.sivalabs.mybatisdemo.mappers package.
  package com.sivalabs.mybatisdemo.mappers;

  import java.util.List;
  import com.sivalabs.mybatisdemo.domain.User;

  public interface UserMapper 
  {

   public void insertUser(User user);
   
   public User getUserById(Integer userId);
   
   public List<User> getAllUsers();
   
   public void updateUser(User user);
   
   public void deleteUser(Integer userId);
   
  }

  

Step#5: Create UserMapper.xml file in src/main/resources folder in com.sivalabs.mybatisdemo.mappers package.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  
<mapper namespace="com.sivalabs.mybatisdemo.mappers.UserMapper">

  <select id="getUserById" parameterType="int" resultType="com.sivalabs.mybatisdemo.domain.User">
     SELECT 
      user_id as userId, 
      email_id as emailId , 
      password, 
      first_name as firstName, 
      last_name as lastName
     FROM USER 
     WHERE USER_ID = #{userId}
  </select>
  <!-- Instead of referencing Fully Qualified Class Names we can register Aliases in mybatis-config.xml and use Alias names. -->
   <resultMap type="User" id="UserResult">
    <id property="userId" column="user_id"/>
    <result property="emailId" column="email_id"/>
    <result property="password" column="password"/>
    <result property="firstName" column="first_name"/>
    <result property="lastName" column="last_name"/>   
   </resultMap>
  
  <select id="getAllUsers" resultMap="UserResult">
   SELECT * FROM USER
  </select>
  
  <insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyProperty="userId">
   INSERT INTO USER(email_id, password, first_name, last_name)
    VALUES(#{emailId}, #{password}, #{firstName}, #{lastName})
  </insert>
  
  <update id="updateUser" parameterType="User">
    UPDATE USER 
    SET
     PASSWORD= #{password},
     FIRST_NAME = #{firstName},
     LAST_NAME = #{lastName}
    WHERE USER_ID = #{userId}
  </update>
  
  <delete id="deleteUser" parameterType="int">
    DELETE FROM USER WHERE USER_ID = #{userId}
  </delete>
  
</mapper>


Step#6: Create MyBatisUtil.java to instantiate SqlSessionFactory.
package com.sivalabs.mybatisdemo.service;

import java.io.IOException;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class MyBatisUtil 
{
 private static SqlSessionFactory factory;

 private MyBatisUtil() {
 }
 
 static
 {
  Reader reader = null;
  try {
   reader = Resources.getResourceAsReader("mybatis-config.xml");
  } catch (IOException e) {
   throw new RuntimeException(e.getMessage());
  }
  factory = new SqlSessionFactoryBuilder().build(reader);
 }
 
 public static SqlSessionFactory getSqlSessionFactory() 
 {
  return factory;
 }
}

Step#7: Create UserService.java in src/main/java folder.
package com.sivalabs.mybatisdemo.service;

import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.sivalabs.mybatisdemo.domain.User;
import com.sivalabs.mybatisdemo.mappers.UserMapper;

public class UserService
{
 
 public void insertUser(User user) {
  SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();
  try{
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  userMapper.insertUser(user);
  sqlSession.commit();
  }finally{
   sqlSession.close();
  }
 }

 public User getUserById(Integer userId) {
  SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();
  try{
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  return userMapper.getUserById(userId);
  }finally{
   sqlSession.close();
  }
 }

 public List<User> getAllUsers() {
  SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();
  try{
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  return userMapper.getAllUsers();
  }finally{
   sqlSession.close();
  }
 }

 public void updateUser(User user) {
  SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();
  try{
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  userMapper.updateUser(user);
  sqlSession.commit();
  }finally{
   sqlSession.close();
  }
  
 }

 public void deleteUser(Integer userId) {
  SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().openSession();
  try{
  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  userMapper.deleteUser(userId);
  sqlSession.commit();
  }finally{
   sqlSession.close();
  }
  
 }

}

Step#8: Create a JUnit Test class to test UserService methods.
package com.sivalabs.mybatisdemo;

import java.util.List;

import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import com.sivalabs.mybatisdemo.domain.User;
import com.sivalabs.mybatisdemo.service.UserService;

public class UserServiceTest 
{
 private static UserService userService;
 
 @BeforeClass
    public static void setup() 
 {
  userService = new UserService();
 }
 
 @AfterClass
    public static void teardown() 
 {
  userService = null;
 }
 
    @Test
 public void testGetUserById() 
 {
  User user = userService.getUserById(1);
  Assert.assertNotNull(user);
  System.out.println(user);
 }
    
    @Test
    public void testGetAllUsers() 
    {
  List<User> users = userService.getAllUsers();
  Assert.assertNotNull(users);
  for (User user : users) 
  {
   System.out.println(user);
  }
  
 }
    
    @Test
    public void testInsertUser() 
    {
     User user = new User();
     user.setEmailId("test_email_"+System.currentTimeMillis()+"@gmail.com");
     user.setPassword("secret");
     user.setFirstName("TestFirstName");
     user.setLastName("TestLastName");
     
     userService.insertUser(user);
  Assert.assertTrue(user.getUserId() != 0);
  User createdUser = userService.getUserById(user.getUserId());
  Assert.assertNotNull(createdUser);
  Assert.assertEquals(user.getEmailId(), createdUser.getEmailId());
  Assert.assertEquals(user.getPassword(), createdUser.getPassword());
  Assert.assertEquals(user.getFirstName(), createdUser.getFirstName());
  Assert.assertEquals(user.getLastName(), createdUser.getLastName());
  
 }
    
    @Test
    public void testUpdateUser() 
    {
     long timestamp = System.currentTimeMillis();
  User user = userService.getUserById(2);
  user.setFirstName("TestFirstName"+timestamp);
     user.setLastName("TestLastName"+timestamp);
     userService.updateUser(user);
  User updatedUser = userService.getUserById(2);
  Assert.assertEquals(user.getFirstName(), updatedUser.getFirstName());
  Assert.assertEquals(user.getLastName(), updatedUser.getLastName());
 }
    
   @Test
   public void testDeleteUser() 
   {
     User user = userService.getUserById(4);
     userService.deleteUser(user.getUserId());
  User deletedUser = userService.getUserById(4);
  Assert.assertNull(deletedUser);   
  
 }
}

Friday, October 12, 2012

Spring3+JPA2+JavaEE6AppServer = Confusion Over Configuration

Spring is great, JavaEE6 is great and latest JavaEE6 Application servers are also great. This post is not a rant on Spring Vs JavaEE6, but my experience of porting a Spring3+JPA2(Hibernate) application on JBoss AS-7.1 App Server.

My application requirement is very simple: Developing a couple of SOAP based webservices using Spring3.1 and JPA2(Hibernate) and host it on JBoss AS 7.1.

So I started creating a multi-module maven project with one jar module containing the service implementations using Spring & JPA and another war module which exposes those services as SOAP based webservices. But the key part is services needs to talk to multiple databases for some of the service methods.

 I am aware of JPA2 integration support from Spring without persistence.xml and cool packagesToScan attribute which makes life a bit easier. I configured 2 dataSources, 2 LocalContainerEntityManagerFactoryBeans, registered 2 JpaTransactionManagers and enabled Annotation based Transaction Management Support.


	<tx:annotation-driven transaction-manager="txnManager1"/>
	<tx:annotation-driven transaction-manager="txnManager2"/>
	
	<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/><!-- This will throw error because it found multiple EntityManagerFactory beans -->
	
	<bean id="txnManager1" 
			class="org.springframework.orm.jpa.JpaTransactionManager"
       		p:entityManagerFactory-ref="emf1"/>
    
    <bean id="txnManager2" 
			class="org.springframework.orm.jpa.JpaTransactionManager"
       		p:entityManagerFactory-ref="emf2"/>       		
       
    <bean id="emf1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
       	<property name="persistenceUnitName" value="Sivalabs1PU"></property>       	
       	<property name="dataSource" ref="dataSource1"></property>
       	<property name="jpaVendorAdapter">
       		<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
         			p:showSql="${hibernate.show_sql}"/>
       	</property>
       	<property name="jpaProperties">
       		<props>
       			<prop key="hibernate.dialect">${hibernate.dialect}</prop>
       			<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
       		</props>
       	</property>
       	<property name="packagesToScan" value="com.sivalabs.springdemo.entities"></property>
       	<property name="loadTimeWeaver">
          <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
        </property>
        
    </bean> 
    
   	<bean id="emf2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
       	<property name="persistenceUnitName" value="Sivalabs2PU"></property>
       	<property name="dataSource" ref="dataSource2"></property>
       	<property name="jpaVendorAdapter">
       		<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
         			p:showSql="${hibernate.show_sql}"/>
       	</property>
       	<property name="jpaProperties">
       		<props>
       			<prop key="hibernate.dialect">${hibernate.dialect}</prop>
       			<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
       		</props>
       	</property>
       	<property name="packagesToScan" value="com.sivalabs.springdemo.entities"></property>
       	<property name="loadTimeWeaver">
          <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
        </property>
        
    </bean> 
	
	<bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="${node1.jdbc.driverClassName}"></property>
		<property name="url" value="${node1.jdbc.url}"></property>
		<property name="username" value="${node1.jdbc.username}"></property>
		<property name="password" value="${node1.jdbc.password}"></property>
	</bean>
	
	<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="${node2.jdbc.driverClassName}"></property>
		<property name="url" value="${node2.jdbc.url}"></property>
		<property name="username" value="${node2.jdbc.username}"></property>
		<property name="password" value="${node2.jdbc.password}"></property>
	</bean>

After this I realized to bind Entitymanager with the correct PersistenceUnit I need to give persistenceUnitName to LocalContainerEntityManagerFactoryBean.

	
	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
		<property name="persistenceUnits" >
	     <map>
	       <entry key="unit1" value="Sivalabs1PU"/>
	       <entry key="unit2" value="Sivalabs2PU"/>
	     </map>
		</property>
	</bean>
	
	<bean id="emf1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
       	<property name="persistenceUnitName" value="Sivalabs1PU"></property>
       	<property name="dataSource" ref="dataSource1"></property>
       	....
		....        
    </bean> 
    
   	<bean id="emf2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
       	<property name="persistenceUnitName" value="Sivalabs2PU"></property>
       	<property name="dataSource" ref="dataSource2"></property>
        ....
		....        
    </bean>

Then in my Service Bean EntityManagers and transaction managers are glued together as follows:

@Service
public class AdminUserService implements UserService
{
	@PersistenceContext(unitName="Sivalabs1PU")
	private EntityManager sivalabs1EM;
	@PersistenceContext(unitName="Sivalabs2PU")
	private EntityManager sivalabs2EM;
	
	@Override
	@Transactional("txnManager1")
	public List<User> getAllUsersFromSivalabs1DB() {
		return sivalabs1EM.createQuery("from User", User.class).getResultList();
	}

	@Override
	@Transactional("txnManager2")
	public List<User> getAllUsersFromSivalabs2DB() {
		return sivalabs2EM.createQuery("from User", User.class).getResultList();
	}
	
}

With this setup now I got the Exception saying "No persistence unit with name 'Sivalabs1PU' found".

Then after some googling I created  META-INF/persistence.xml file as follows:



<persistence>

   <persistence-unit name="Sivalabs1PU" transaction-type="RESOURCE_LOCAL">   		
   </persistence-unit>
   
   <persistence-unit name="Sivalabs2PU"  transaction-type="RESOURCE_LOCAL">   		
   </persistence-unit>
   
</persistence>

Now the persistence unit name error got resolved and got other Exception saying "User is not mapped [from User]". The User class is annotated with @Entity and is in "com.sivalabs.springdemo.entities" package which I configured to "packagesToScan" attribute. I didn't understand why "packagesToScan" attribute is not working which is working fine without persistence.xml. So for time being I configured entity classes in persistence.xml file.

<persistence>

   <persistence-unit name="Sivalabs1PU" transaction-type="RESOURCE_LOCAL">   	
		<class>com.sivalabs.springdemo.entities.User</class>   
   </persistence-unit>
   
   <persistence-unit name="Sivalabs2PU"  transaction-type="RESOURCE_LOCAL">   	
		<class>com.sivalabs.springdemo.entities.User</class>
   </persistence-unit>
   
</persistence>

Finally when I ran my JUnit Test which invokes AdminUserService methods everything looks good and working fine. Then I deployed the war file on JBoss AS 7.1 Server then again got a bunch of errors. JBoss is complaining that "Connection cannot be null when 'hibernate.dialect' not set" .... "[PersistenceUnit: Sivalabs1PU] Unable to build EntityManagerFactory".

After thinking for a couple of minutes, I understood that JBoss server is trying to do what it is supposed to do with "Convention Over Configuration" rules. JBoss is trying to create EntityManagerFactory because it found META-INF/persistence.xml in classpath. But as it doesn't contain jdbc connection details its throwing Error. 

Again after some googling I found we can rename persistence.xml to something else(spring-persistence.xml) and hook up this new name with Spring as follows:

	<bean id="emf1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
       	<property name="persistenceUnitName" value="Sivalabs1PU"></property>
		<property name="persistenceXmlLocation" value="classpath:META-INF/spring-persistence.xml"/>
       	<property name="dataSource" ref="dataSource1"></property>
       	....
		....        
    </bean> 
    
   	<bean id="emf2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
       	<property name="persistenceUnitName" value="Sivalabs2PU"></property>
		<property name="persistenceXmlLocation" value="classpath:META-INF/spring-persistence.xml"/>
       	<property name="dataSource" ref="dataSource2"></property>
        ....
		....        
    </bean>

Finally I got this application working on my JBoss AS 7.1 successfully(Still I don't know how many other holes are there that I haven't yet found).

But here I didn't understand few Spring concepts:
1. When I try to give persistenceUnitName why Spring is checking for that name to be existed in persistence.xml? Anyway that persistence.xml doesn't contain anything exception the unit-name!!

2. Why packagesToScan mechanism is failing when used with persistence.xml? Is it a Spring Bug?

Everything seems to be working fine except one thing is missing, a smile on my face which usually I have when working with Spring and Tomcat :-(

I like Spring framework very much and I am using it since 2006 and I do enjoy while writing Spring code. That doesn't mean I don't like CDI, EJB3, JAX-RS :-)

 Anyway, with all the above exercise I feel like Spring3+JPA2+JavaEE6AppServer=Confusion Over Configuration and it is my(an average java developer) opinion only.

Again say one more time : Spring is great, JavaEE6 is great and latest JavaEE6 Application servers are also great :-).

Tuesday, August 28, 2012

Keep The Code Clean: WatchDog & SpotTheBug Approach


Before going to discuss "WatchDog & SpotTheBug Approach", let me give a brief context on what is the needs for this.

Three months back I was asked to write core infrastructure code for our new application which uses all the latest and greatest technologies.
I have written the infrastructure code and implemented 2 usecases to demonstrate which logic should go into which layer and the code looks good(atleast to me :-)). Then I moved on to my main project and I was hearing that the project that i designed(from Now on-wards I will refer this as ProjectA) is going well.

After 3 months last week one of the developer of ProjectA came to me to help him in resolving some JAXB Marshalling issue. Then I imported the latest code into eclipse and started looking into the issue and I was literally shocked by looking at the messy code. First I resolved that issue and started looking into whole code and I was speechless. How come the code become such a mess in this short span of time, it is just 3 months.


  • There are Date Formatting methods in almost every Service class(Copy&Paste with different names)
  • There are Domain classes with 58 String properties and setters/getters. Customer class contains homeAddressLine1, homeAddressLine2, homeCity.., officeAddrLine1, officeAddrLine2, officeCity... There is no Address class.
  • In some classes XML to Java marshaling is done using JAXB and in some other classes using XStream and in some other places constructing XML string manually even though there is core utilities module with lots of XML marshaling utility methods.
  • In some classes SLF4J Logger is used and in some places Log4J Logger is being used.

and the list goes on...

So what just happend? Where is the problem?

We started this project by pledging to keep the code clean and highly maintainable/enhanceable. But now it is in worst possible state.

Somehow it is understandable if the code is legacy code and is messy because today's latest way of doing things becomes tomorrow's legacy and bad approach like externalizing the application configuration into XML was the way to go sometime back and now it became XML hell with shiny new Annotations. I am pretty sure that in a couple of years we will see "Get Rid of Annotation Hell by Using SomeNew Gr8 Way". 

But in my case it is just 3 months old project.

When I think about the causes of why that code becomes such a mess I end-up with never-ending list of reasons:

  • Tight dead lines
  • Incompetent developers
  • Not using code quality checking tools
  • No code reviews
  • No time to clean the messy code

etc etc

So whatever the reason your code will become messy after sometime, especially when more number of people are working the project.

The worst part is you can't blame anyone. Developer will say I have no time to cleanup the code as I have assigned high priority tasks. Tech Lead is busy in analysing and assigning the new tasks to developers.
Manager is busy in aggregating the team's task status reports to satisfy his boss. Architect is busy in designing the new modules for new third party integration services. QA people are busy in preparing/executing their test cases for upcoming releases.

So whose responsibility it is to clean the code? Or in other way, How can we keep code clean even with all the above said Busy circumstances?

Before going to explain How "WatchDog & SpotTheBug Approach" works let me tell you another story.

3 years back I worked on a banking project which is well designed, well organised and well written code that I have ever seen so far. That project started almost 10 years back, but still the code quality is very good. How is it possible?

The only reason is If any developer check-in the code with some bad code like adding duplicate utility methods then within 4 hours that developer will recieve an email from a GUY asking for the explanation what is the need to add that method when that utility method is already available in core-utilities module. In case there is no valid reason, that developer has to open a new defect with "Cleaning Bad Code" in the defect title, assign the defect to himself and change the code and should check-in the files ASAP.

With this process, every team member in our team used to tripple check the code before checking into repository.

I think this is best possible way to keep the code clean. By now you may have clue on what I mean by "WatchDog". Yes, I called the GUY as WatchDog. First of all, sorry for calling such an important role as Dog but it better describe what that guy will do. It will bark as soon as it saw some bad code.

Need for WatchDog:

As I mentioned above, everyone in the team might be busy with their high-priority tasks. They might not be able to spend time on cleaning the code. Also from the Business perspective Adding new customer-requested features might be high-priority than cleaning the code. Sometime even though Business know that in long run there is a chance that entire application becomes un-maintainable if they don't cleanup the mess they will have to satisfy their customer first with some quick new features and will opt for short-term benefits.

We have plenty of Quality Checking tools like PMD, FindBugs, Sonar. But does these tools suggest to create an Address class instead of repeating all address properties for different type of addresses as i mentioned above. Does these tools suggest you to use same xml marshalling library across the project. As far as I know, they won't.

So if you really want your software/product to sustain over time, I would suggest to hire a dedicated WatchDog(Human Being).

The WatchDog's primary responsibilities would be:

  • Continuously checking for the code smells, duplicate methods, coding standards violations and send the report to entire team.
  • If possible point out the existing utility to use instead of creating duplicate methods.
  • Checking for design violations like establishing Database Connection or Transaction management code in wrong places(web layer for ex).
  • Checking for cyclic dependencies for between modules.
  • Exploring and suggesting well established, tested generic libraries like apache commons-*.jars, Google Guava instead of writing home grown solutions(I feel like instead of writing home grown Cache Management better to use Guava Cache,but YMMV)


So far so good if the WatchDog does its job well. What if the WatchDog itself is inefficient?? What if WatchDog is not Skilled enough to perform its job? Who is going to check whether WatchDog is doing good or not?  Here "SpotTheBug" program comes into picture.

"SpotTheBug"
I strongly believe in having a friendly culture to encourage the developers to come up with thoughts to better the software.

Every week each team member should come up with 3 points to better/clean the code. They can be: Bad code Identification, Better Design, New Features etc.

Instead of just saying that code is bad code, he has to specify why he is feeling that code is bad, how to rewrite it in better way and what would be the impact.

Based on the effectiveness of the points, value-points should be given to the developer and those points should definitely be considered in performance review(There should be some motivation right :-)).

With WatchDog and SpotTheBug programs in place, if the team can identify the bad code before the WatchDog caught it then it is going to be a negetive point for WatchDog. If WatchDog continuously getting negative points then it is time to evaluate the effectiveness of WatchDog itself.

By using this WatchDog & SpotTheBug approach combined with proper usage of Code Quality Checking Tools(FindBugs, PMD, Sonar) we can make sure the code is clean to the maximum extent.




Tuesday, June 19, 2012

How I explained Dependency Injection to My Team

Recently our company started developing a new java based web application and after some evaluation process we decided to use Spring.

But many of the team members are not aware of Spring and Dependency Injection principles.
So I was asked to give a crash course on what is Dependency Injection and basics on Spring.

Instead of telling all the theory about IOC/DI I thought of explaining with an example.

Requirement: We will get some Customer Address and we need to validate the address.
After some evaluation we thought of using Google Address Validation Service.

 Legacy(Bad) Approach:

Just create an AddressVerificationService class and implement the logic.

Assume GoogleAddressVerificationService is a service provided by Google which takes Address as a String and Return longitude/latitude.

class AddressVerificationService 
{
   public String validateAddress(String address)
 {
 GoogleAddressVerificationService gavs = new GoogleAddressVerificationService();
  String result = gavs.validateAddress(address);  
  return result;
 }
}

Issues with this approach: 
 1. If you want to change your Address Verification Service Provider you need to change the logic.
 2. You can't Unit Test with some Dummy AddressVerificationService (Using Mock Objects)

 Due to some reason Client ask us to support multiple AddressVerificationService Providers and we need to determine which service to use at runtime.

To accomidate this you may thought of changing the above class as below:

class AddressVerificationService
{
//This method validates the given address and return longitude/latitude details.
 public String validateAddress(String address)
 {
  String result = null;
  int serviceCode = 2; // read this code value from a config file
  if(serviceCode == 1)
  {
   GoogleAddressVerificationService googleAVS = new GoogleAddressVerificationService();
   result = googleAVS.validateAddress(address);
  } else if(serviceCode == 2)
  {
   YahooAddressVerificationService yahooAVS = new YahooAddressVerificationService();
   result = yahooAVS.validateAddress(address);
  }
  return result;
 }
}

Issues with this approach: 


1. Whenever you need to support a new Service Provider you need to add/change logic using if-else-if.
 2. You can't Unit Test with some Dummy AddressVerificationService (Using Mock Objects)

 IOC/DI Approach: 

 In the above approaches AddressVerificationService is taking the control of creating its dependencies.
 So whenever there is a change in its dependencies the AddressVerificationService will change.

 Now let us rewrite the AddressVerificationService using IOC/DI pattern.

 class AddressVerificationService
 {
  private AddressVerificationServiceProvider serviceProvider;
  
  public AddressVerificationService(AddressVerificationServiceProvider serviceProvider) {
   this.serviceProvider = serviceProvider;
  }
  
  public String validateAddress(String address)
  {
   return this.serviceProvider.validateAddress(address);
  }
 }
 
 interface AddressVerificationServiceProvider
 {
  public String validateAddress(String address);
 }
 

Here we are injecting the AddressVerificationService dependency AddressVerificationServiceProvider.

Now let us implement the AddressVerificationServiceProvider with multiple provider services.

 class YahooAVS implements AddressVerificationServiceProvider
 {
  @Override
  public String validateAddress(String address) {
   System.out.println("Verifying address using YAHOO AddressVerificationService");
   return yahooAVSAPI.validate(address);
  }  
 }

 class GoogleAVS implements AddressVerificationServiceProvider
 {
  @Override
  public String validateAddress(String address) {
   System.out.println("Verifying address using Google AddressVerificationService");
   return googleAVSAPI.validate(address);
  }
 }
 
Now the Client can choose which Service Provider's service to use as follows:

 AddressVerificationService verificationService = null;
 AddressVerificationServiceProvider provider = null;
 provider = new YahooAVS();//to use YAHOO AVS
 provider = new GoogleAVS();//to use Google AVS
 
 verificationService = new AddressVerificationService(provider);
 String lnl = verificationService.validateAddress("HitechCity, Hyderabad");
 System.out.println(lnl);
 

For Unit Testing we can implement a Mock AddressVerificationServiceProvider.

 class MockAVS implements AddressVerificationServiceProvider
 {
  @Override
  public String validateAddress(String address) {
   System.out.println("Verifying address using MOCK AddressVerificationService");
   return "<response><longitude>123</longitude><latitude>4567</latitude>";
  }
 }
 
 AddressVerificationServiceProvider provider = null;
 provider = new MockAVS();//to use MOCK AVS  
 AddressVerificationServiceIOC verificationService = new AddressVerificationServiceIOC(provider);
 String lnl = verificationService.validateAddress("Somajiguda, Hyderabad");
 System.out.println(lnl);
 

With this approach we elemenated the issues with above Non-IOC/DI based approaches.
 1. We can provide support for as many Provides as we wish. Just implement AddressVerificationServiceProvider and inject it.
 2. We can unit test using Dummy Data using Mock Implementation.


So by following Dependency Injection principle we can create interface-based loosely-coupled and easily testable services.

Thursday, April 26, 2012

@GeneratedValue not setting up auto increment in mysql and h2 dialects

Hi,
In earlier versions of Hibernate if we want to have an auto_increment primary key we can use the following:

@Id @GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="user_id")
private Integer userId;

But in latest version of Hibernate(may be Hibernate4, whatever is used in JBoss AS7) this doesn't work as expected. The generated table primary key is not auto_increment column.

To resolve this configure <property name="hibernate.id.new_generator_mappings" value="false"> in persistence.xml.

Monday, January 16, 2012

Java Best Practices : Building Safe Domain Objects

Domain objects are the core building blocks of any application. These are the fine grained objects which carries the information about the problem domain model.
Generally domain objects will be created as dumb data carriers with setters/geters without having any logic. But this will cause huge problem in long run.
If you build the domain objects with dumb setters and getters we will end up in writing null checks all over the places.

I bet many of us have seen the code snippets like:

User user = ....;
if(user!=null)
{
 String email = user.getEmail();
 if(email != null && StringUtils.trimToNull(email) != null)
 {
  emailService.sendEmail(....);
 }
 else
 {
  throw new Exception("Email should not be null/blank");
 }

}

Here email address of User object should not be null at all(It could be a not null property in database).

But with dumb domain objects with only setters/getters we will end up writing code to check for nulls as mentioned above.

We can get rid of this null checks in all over the places we can use Builder pattern.

Assume we need to write a domain Object User with properties id, firstname, lastname, email, dob, phone.
Among them id, firstname, lastname, email properties are mandatory and should not be null or blank.

In this case we can write the User class using Builder pattern as follows:

package com.sivalabs.core.model;

import java.util.Date;

/**
 * @author Siva
 *
 */
public class User 
{
 private Integer id;
 private String firstname;
 private String lastname;
 private String email;
 private Date dob;
 private String phone;
 
 private User()
 {
 }
 
 private User(Integer id, String firstname, String lastname, String email) 
 {
  this.id = id;
  this.firstname = firstname;
  this.lastname = lastname;
  this.email = email;
 }

 public static final User build(Integer id, String firstname, String lastname, String email)
 {
  if(id == null || id < 0){
   throw new IllegalArgumentException("Id should not be null or negetive.");
  }
  if(firstname == null || firstname.trim().length()==0){
   throw new IllegalArgumentException("firstname should not be null or blank.");
  }
  if(lastname == null || lastname.trim().length()==0){
   throw new IllegalArgumentException("lastname should not be null or blank.");
  }
  if(email == null || email.trim().length()==0){
   throw new IllegalArgumentException("email should not be null or blank.");
  }
  if(!email.contains("@")){
   throw new IllegalArgumentException("Invalid email address.");
  }
  return new User(id,firstname, lastname, email);
 }
 
 public Integer getId() {
  return id;
 } 
 public String getFirstname() {
  return firstname;
 }
 
 public String getLastname() {
  return lastname;
 }
 
 public String getEmail() {
  return email;
 }
 
 public Date getDob() {
  return new Date(dob.getTime());
 }
 
 public User dob(Date dob) {
  this.dob = new Date(dob.getTime());
  return this;
 }
 public String getPhone() {
  return phone;
 }
 public User phone(String phone) {
  this.phone = phone;
  return this;
 } 
 
}
Following are the steps to build safe domain objects:

1. Make default constructor as private preventing others creating empty instances.  
2. Create a private parametrized constructor with mandatory arguments only.  
3. Provide a public static build() method taking mandatory arguments, validate them and then build the object using parametrized constructor.  
4. Create setter methods (I have used Method chaining here) for optional properties. 
 
With this procedure I need not check for nulls for the mandatory arguments becuase if I have a non-null user object means it contains valid values for mandatory properties.

Tuesday, October 4, 2011

A good collection of Java Utility classes

Today While surfing net I reached Impala framework's source code at googlecode.
I haven't gone through Impala framework. But there are plenty of Java Utilities in its core module which could be helpful for our day to day work.

FileUtils.java
InstantiationUtils.java
MemoryUtils.java
ObjectMapUtils.java
ObjectUtils.java
ParseUtils.java
PathUtils.java
PropertyUtils.java
ReflectionUtils.java
ResourceUtils.java
SerializationUtils.java
StringBufferUtils.java
URLUtils.java
XMLDomUtils.java

Just thought of sharing the link.

Impala Project Home

Impala Core Utilities

Monday, August 22, 2011

Are frameworks making developers dumb?

Last week I got to take interviews to hire senior java developers with around 5 years of experience. But after the interview process is over I felt like the frameworks makes developers life easier but at the same time making them dumb.

Everyone puts almost all the new frameworks on their resume claiming they have "Strong, working experience on Spring, Hibernate, Web Services etc".

Here is how the interviews went on.

Me: You have used Spring in your latest project. What are the advantages of using Spring?
Interviewee: We can configure beans in XML and it will take care of instantiating and give it to us.

Me: If Spring is for only creating objects why is it required at all, I can directly instantiate the dependencies using "new". Why should I configure the class names in XML and get the object from Spring?

Interviewee: If tomorrow we want to create another implementation of our interface we can create new implementation and update the XML configuration to use new impl. We don't need to change Java class and compile them.
Me: But you are writing a new Java class, so obviously you need to compile the project.
Regarding XML change, 99% of the times your XML will be packaged in war or ear file.
So you will run ANT script and create the war with the all the new changes.
Then your point of "if it is XML i don't need to compile" is not a valid point.

Interviewee: Hmmm, But the Dependency Injection design pattern suggests to follow this way.
Me: OK. I am done with the interview. Our HR will get back to you. :-)

Interview with another guy:

Me: Can you explain about your latest project and what technologies have you used?
Interviewee: It is some XYZ System and we are using Spring, Hibernate, REST WebServices.
Me: Ok. Can you explain something about RESTful architecture?
Interviewee: We can develop RESTful application by using @RequestMapping(value="/url", method="POST"). And also we can use PUT, DELETE methods.
Me: That OK, but what is the concept of RESTful architecture?
Interviewee: That's what I am explaining. If you use @RequestMapping(value="/url", method="POST") you can develop RESTful application.

Me: Ok, How good are you in Hibernate?
Interviewee: I am using Hibernate for the last 2 years. I am very good in using Hibernate.
Me: What are the advantages of using Hibernate over JDBC?
Interviewee: By using we don't need to write anything to interact with database, Hibernate will take care of.
Me: How Hibernate comes to know about your project requirement?
Interviewee: If we use Hibernate it will take care saving, updating and fetching data from database.
Me: Uffffffuuuuu... OK.. In your free time do you read any technology related blogs?
Interviewee: Yeah, why not. That how I learn Hibernate in-depth.
Me : Very Good, nice talking to you. Our HR will get back to you. :-)

Interview process went on like this...

I strongly believe frameworks will increase developer productivity. But the developers should try to understand how the framework is doing the stuff. You need not learn all the internal working mechanisms of frameworks. If you are really good at Servlets and JSP then it is very easy to understand any Java Web framework like Struts, SpringMVC etc.If you aren't good at the basics then obviously for every other question reply would be.. "framework's annotation/xml will execute this"

I strongly recommend the people who want to start their career as a Java developer to work on Core Java, Servlets, JSP for sometime.Then only one can understand the frameworks in proper way.

Monday, May 30, 2011

Spring + Quartz + JavaMail Integration Tutorial

Quartz is a job scheduling framework which is used to schedule the jobs to be executed on the specified time schedule.
JavaMail is an API to send/recieve emails from Java Applications.

Spring has integration points to integrate Quartz and JavaMail which makes easy to use those APIs.

Lets create a small demo application to show how to integrate Spring + Quartz + JavaMail.

Our application is to send birthday wishes emails to friends everyday at 6 AM.

Email.java

package com.sivalabs.reminders;

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

public class Email 
{
 private String from;
 private String[] to;
 private String[] cc;
 private String[] bcc;
 private String subject;
 private String text;
 private String mimeType;
 private List<Attachment> attachments = new ArrayList<Attachment>();
 
 public String getFrom()
 {
  return from;
 }
 public void setFrom(String from)
 {
  this.from = from;
 }
 public String[] getTo()
 {
  return to;
 }
 public void setTo(String... to)
 {
  this.to = to;
 }
 public String[] getCc()
 {
  return cc;
 }
 public void setCc(String... cc)
 {
  this.cc = cc;
 }
 public String[] getBcc()
 {
  return bcc;
 }
 public void setBcc(String... bcc)
 {
  this.bcc = bcc;
 }
 public String getSubject()
 {
  return subject;
 }
 public void setSubject(String subject)
 {
  this.subject = subject;
 }
 public String getText()
 {
  return text;
 }
 public void setText(String text)
 {
  this.text = text;
 }
 public String getMimeType()
 {
  return mimeType;
 }
 public void setMimeType(String mimeType)
 {
  this.mimeType = mimeType;
 }
 public List<Attachment> getAttachments()
 {
  return attachments;
 }
 public void addAttachments(List<Attachment> attachments)
 {
  this.attachments.addAll(attachments);
 }
 public void addAttachment(Attachment attachment)
 {
  this.attachments.add(attachment);
 }
 public void removeAttachment(int index)
 {
  this.attachments.remove(index);
 }
 public void removeAllAttachments()
 {
  this.attachments.clear();
 }
}

Attachment.java
package com.sivalabs.reminders;

public class Attachment
{
 private byte[] data;
 private String filename;
 private String mimeType;
 private boolean inline;
 
 public Attachment()
 {
 }
 
 public Attachment(byte[] data, String filename, String mimeType)
 {
  this.data = data;
  this.filename = filename;
  this.mimeType = mimeType;
 }
 public Attachment(byte[] data, String filename, String mimeType, boolean inline)
 {
  this.data = data;
  this.filename = filename;
  this.mimeType = mimeType;
  this.inline = inline;
 }
 public byte[] getData()
 {
  return data;
 }
 public void setData(byte[] data)
 {
  this.data = data;
 }
 public String getFilename()
 {
  return filename;
 }
 public void setFilename(String filename)
 {
  this.filename = filename;
 }

 public String getMimeType()
 {
  return mimeType;
 }

 public void setMimeType(String mimeType)
 {
  this.mimeType = mimeType;
 }

 public boolean isInline()
 {
  return inline;
 }

 public void setInline(boolean inline)
 {
  this.inline = inline;
 }
 
}

EmailService.java
package com.sivalabs.reminders;

import java.util.List;

import javax.activation.DataSource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.mail.util.ByteArrayDataSource;

import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;

public class EmailService 
{
 private JavaMailSenderImpl mailSender = null;
 public void setMailSender(JavaMailSenderImpl mailSender)
 {
  this.mailSender = mailSender;
 }
 
 public void sendEmail(Email email) throws MessagingException {
  MimeMessage mimeMessage = mailSender.createMimeMessage();
  // use the true flag to indicate you need a multipart message
  boolean hasAttachments = (email.getAttachments()!=null && 
         email.getAttachments().size() > 0 );
  MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, hasAttachments);
  helper.setTo(email.getTo());
  helper.setFrom(email.getFrom());
  helper.setSubject(email.getSubject());
  helper.setText(email.getText(), true);
  
  List<Attachment> attachments = email.getAttachments();
     if(attachments != null && attachments.size() > 0)
     {
      for (Attachment attachment : attachments) 
      {
          String filename = attachment.getFilename() ;
          DataSource dataSource = new ByteArrayDataSource(attachment.getData(), 
                 attachment.getMimeType());
          if(attachment.isInline())
          {
           helper.addInline(filename, dataSource);
          }else{
           helper.addAttachment(filename, dataSource);
          }
   }
     }
  
  mailSender.send(mimeMessage);
 }
}


BirthdayWisherJob.java
package com.sivalabs.reminders;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.mail.MessagingException;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class BirthdayWisherJob extends QuartzJobBean
{
 
 private EmailService emailService;
 public void setEmailService(EmailService emailService)
 {
  this.emailService = emailService;
 }
 
 @Override
 protected void executeInternal(JobExecutionContext context) throws JobExecutionException
 {
  System.out.println("Sending Birthday Wishes... ");
  List<User> usersBornToday = getUsersBornToday();
  for (User user : usersBornToday) 
  {
   try 
   {
    Email email = new Email();
    email.setFrom("admin@sivalabs.com");
    email.setSubject("Happy BirthDay");
    email.setTo(user.getEmail());
    email.setText("

Dear "+user.getName()+ ", Many Many Happy Returns of the day :-)

"); byte[] data = null; ClassPathResource img = new ClassPathResource("HBD.gif"); InputStream inputStream = img.getInputStream(); data = new byte[inputStream.available()]; while((inputStream.read(data)!=-1)); Attachment attachment = new Attachment(data, "HappyBirthDay", "image/gif", true); email.addAttachment(attachment); emailService.sendEmail(email); } catch (MessagingException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } } private List<User> getUsersBornToday() { List<User> users = new ArrayList<User>(); User user1 = new User("Siva Prasad", "sivaprasadreddy.k@gmail.com", new Date()); users.add(user1); User user2 = new User("John", "abcd@gmail.com", new Date()); users.add(user2); return users; } }

applicationContext.xml


 
 
  
   <ref bean="birthdayWisherCronTrigger" />
  
 
 
 
  <property name="jobDetail" ref="birthdayWisherJob" />
  <!-- run every morning at 6 AM -->
  <property name="cronExpression" value="0/5 * * * * ?" />
 

 
  <property name="jobClass" value="com.sivalabs.reminders.BirthdayWisherJob" />
  
   
    
   
  
 
 
 
  
 
 
 
  <property name="defaultEncoding" value="UTF-8"/> 
  <property name="host" value="smtp.gmail.com" />
  <property name="port" value="465" />
  <property name="protocol" value="smtps" />
  <property name="username" value="admin@gmail.com"/>
  <property name="password" value="*****"/>
  
   
    true
    true
    true
   
  
 
 


TestClient.java
package com.sivalabs.reminders;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestClient {

 
 public static void main(String[] args) 
 {
  ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");  
 }

}

Sending Email with Attachments using JavaMail

We can send emails using JavaMail API.
Instead of directly using JavaMail API here is a small utility to send emails which shields the user from JavaMail internals.

EmailConfiguration.java

package com.sivalabs.email;
import java.util.Properties;

public class EmailConfiguration
{
 private Properties properties = new Properties();
 
 public static final String SMTP_HOST = "mail.smtp.host";
 public static final String SMTP_AUTH = "mail.smtp.auth";
 public static final String SMTP_TLS_ENABLE = "mail.smtp.starttls.enable";
 public static final String SMTP_AUTH_USER = "smtp.auth.user";
 public static final String SMTP_AUTH_PWD = "smtp.auth.pwd";
 public static final String DEBUG = "debug";
 
 public Properties getProperties()
 {
  return this.properties;
 }
 
 public void setProperty(String key, String value)
 {
  this.properties.put(key, value);
 }
 
 public void addProperties(Properties props)
 {
  this.properties.putAll(props);
 }
 
 public String getProperty(String key)
 {
  return this.properties.getProperty(key);
 }
}

Email.java

package com.sivalabs.email;
import java.util.ArrayList;
import java.util.List;

public class Email 
{
 private String from;
 private String[] to;
 private String[] cc;
 private String[] bcc;
 private String subject;
 private String text;
 private String mimeType;
 private List<Attachment> attachments = new ArrayList<Attachment>();
 
 public String getFrom()
 {
  return from;
 }
 public void setFrom(String from)
 {
  this.from = from;
 }
 public String[] getTo()
 {
  return to;
 }
 public void setTo(String... to)
 {
  this.to = to;
 }
 public String[] getCc()
 {
  return cc;
 }
 public void setCc(String... cc)
 {
  this.cc = cc;
 }
 public String[] getBcc()
 {
  return bcc;
 }
 public void setBcc(String... bcc)
 {
  this.bcc = bcc;
 }
 public String getSubject()
 {
  return subject;
 }
 public void setSubject(String subject)
 {
  this.subject = subject;
 }
 public String getText()
 {
  return text;
 }
 public void setText(String text)
 {
  this.text = text;
 }
 public String getMimeType()
 {
  return mimeType;
 }
 public void setMimeType(String mimeType)
 {
  this.mimeType = mimeType;
 }
 public List<Attachment> getAttachments()
 {
  return attachments;
 }
 public void addAttachments(List<Attachment> attachments)
 {
  this.attachments.addAll(attachments);
 }
 public void addAttachment(Attachment attachment)
 {
  this.attachments.add(attachment);
 }
 public void removeAttachment(int index)
 {
  this.attachments.remove(index);
 }
 public void removeAllAttachments()
 {
  this.attachments.clear();
 }
}

Attachment.java

package com.sivalabs.email;

public class Attachment
{
 private byte[] data;
 private String filename;
 private String mimeType;
 
 public Attachment()
 {
 }
 
 public Attachment(byte[] data, String filename, String mimeType)
 {
  super();
  this.data = data;
  this.filename = filename;
  this.mimeType = mimeType;
 }

 public byte[] getData()
 {
  return data;
 }
 public void setData(byte[] data)
 {
  this.data = data;
 }
 public String getFilename()
 {
  return filename;
 }
 public void setFilename(String filename)
 {
  this.filename = filename;
 }

 public String getMimeType()
 {
  return mimeType;
 }

 public void setMimeType(String mimeType)
 {
  this.mimeType = mimeType;
 }
 
}

EmailService.java

package com.sivalabs.email;

import java.util.List;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;

public class EmailService 
{
 private EmailConfiguration configuration = null;
 private Authenticator auth =null;
 
 public EmailService(EmailConfiguration configuration)
 {
  this.configuration = configuration;
  this.auth = this.buildSmtpAuthenticator();     
 }
 
 private Authenticator buildSmtpAuthenticator()
 {
  String emailId = configuration.getProperty(EmailConfiguration.SMTP_AUTH_USER);
  String password = configuration.getProperty(EmailConfiguration.SMTP_AUTH_PWD);
  return new SMTPAuthenticator(emailId, password);
 }
 
 public void sendEmail(Email email)
 {
  Session session = Session.getDefaultInstance(this.configuration.getProperties(), auth);
  boolean debug = Boolean.valueOf(this.configuration.getProperty(EmailConfiguration.DEBUG));
     session.setDebug(debug);
     
     try 
     {
      Message msg = this.buildEmailMessage(session, email);
   Transport.send(msg);
  } 
     catch (MessagingException e) 
  {
   throw new RuntimeException(e);
  }     
 }
 
 private Message buildEmailMessage(Session session, Email email) throws MessagingException
 {
  Message msg = new MimeMessage(session);
     msg.setSubject(email.getSubject());
     this.addRecievers(msg, email);
     Multipart multipart = new MimeMultipart();
     this.addMessageBodyPart(multipart, email);
     this.addAttachments(multipart, email);   
        msg.setContent(multipart);
     return msg;
 }
 
 private void addRecievers(Message msg, Email email) throws MessagingException
 {
  InternetAddress from = new InternetAddress(email.getFrom());
     msg.setFrom(from);
     
     InternetAddress[] to = this.getInternetAddresses(email.getTo());
     msg.setRecipients(Message.RecipientType.TO, to);

     InternetAddress[] cc = this.getInternetAddresses(email.getCc());
     msg.setRecipients(Message.RecipientType.CC, cc);

     InternetAddress[] bcc = this.getInternetAddresses(email.getBcc());
     msg.setRecipients(Message.RecipientType.BCC, bcc);

 }
 private void addMessageBodyPart(Multipart multipart, Email email) throws MessagingException
 {
   BodyPart messageBodyPart = new MimeBodyPart();
   messageBodyPart.setContent(email.getText(), email.getMimeType());      
   multipart.addBodyPart(messageBodyPart);      
 }
 private void addAttachments(Multipart multipart, Email email) throws MessagingException
 {
  List<Attachment> attachments = email.getAttachments();
     if(attachments != null && attachments.size() > 0)
     {
      for (Attachment attachment : attachments) 
      {
       BodyPart attachmentBodyPart = new MimeBodyPart();
          String filename = attachment.getFilename() ;
          DataSource source = new ByteArrayDataSource(attachment.getData(), 
                 attachment.getMimeType());
          attachmentBodyPart.setDataHandler(new DataHandler(source));
          attachmentBodyPart.setFileName(filename);
          multipart.addBodyPart(attachmentBodyPart);
   }
     }  
 }
 private InternetAddress[] getInternetAddresses(String... addresses) 
       throws AddressException
 {
  if(addresses == null || addresses.length == 0)
  {
   return null;
  }
  InternetAddress[] iAddresses = new InternetAddress[addresses.length];
     for (int i = 0; i < addresses.length; i++)
     {
      iAddresses[i] = new InternetAddress(addresses[i]);
     }
     return iAddresses;
 }
}

class SMTPAuthenticator extends javax.mail.Authenticator
{
 private String username;
 private String password;
 
    public SMTPAuthenticator(String username, String password) {
  this.username = username;
  this.password = password;
 }
    
 public PasswordAuthentication getPasswordAuthentication()
    {
        return new PasswordAuthentication(username, password);
    }
}
Add the mail.jar, activation.jar to the classpath. Here is the TestClient on how to use the EmailService Utility.
package com.sivalabs.email;

public class EmailClient
{
 public static void main(String[] args)
 {
  EmailConfiguration configuration = new EmailConfiguration();
  configuration.setProperty(EmailConfiguration.SMTP_HOST, "smtp.gmail.com");
  configuration.setProperty(EmailConfiguration.SMTP_AUTH, "true");
  configuration.setProperty(EmailConfiguration.SMTP_TLS_ENABLE, "true");
  configuration.setProperty(EmailConfiguration.SMTP_AUTH_USER, "xyz@gmail.com");
  configuration.setProperty(EmailConfiguration.SMTP_AUTH_PWD, "**********");
  
  EmailService emailService = new EmailService(configuration);
  Email email = new Email();
  email.setFrom("sivaprasadreddy.k@gmail.com");
  email.setTo("sivaprasadreddy_k@yahoo.co.in");
  email.setCc("sivaprasadreddy.k@gmail.com");
  
  email.setSubject("Test Mail from SivaLabs");
  email.setText("Hi, 

This is a test email from Siva Labs

"); email.setMimeType("text/html"); Attachment attachment1 = new Attachment("ABCDEFGH".getBytes(), "test1.txt","text/plain"); email.addAttachment(attachment1); Attachment attachment2 = new Attachment("XYZZZZZZ".getBytes(), "test2.txt","text/plain"); email.addAttachment(attachment2); emailService.sendEmail(email); } }

Tuesday, May 17, 2011

SpringMVC + Hibernate Error: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

While developing a web application using SpringMVC and Hibernate I got "No Hibernate Session bound to thread Exception" becuase of some configuration issue.
Here I am going to explain how I resolved the issue.

I used the SpringMVC/@Controller approach and configured the Web related Spring configuration in dispatcher-servlet.xml as follows:

 <context:annotation-config"/>
 <context:component-scan base-package="com.sivalabs"/>
 
 
 

 
  
 



I have configured my business serices and DAOs in applicationContext.xml as follows:

 
 <context:component-scan base-package="com.sivalabs"/>
 <context:property-placeholder location="classpath:app-config.properties"/>
 
 <tx:annotation-driven/>
 
 
 
 
     
     
       
         UserAccount.hbm.xml
         Contact.hbm.xml
       
     
     
       
   ${hibernate.dialect}
   ${hibernate.show_sql}
   
     
   
 
 
  .....
  .....
 


To enable the transaction management I have used @Transactional annotation on my business services.
package com.sivalabs.homeautomation.useraccounts;
@Service
@Transactional
public class UserAccountsService 
{
 @Autowired
 private UserAccountsDAO userAccountsDAO;
 
 public UserAccount login(Credentials credentials) {
  return userAccountsDAO.login(credentials);
 }
}

But when I invoked UserAccountsService.login() method I got the the below error:
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
 at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
 at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:544)
 at com.sivalabs.homeautomation.useraccounts.UserAccountsDAO.login(UserAccountsDAO.java:30)
 at com.sivalabs.homeautomation.useraccounts.UserAccountsService.login(UserAccountsService.java:25)
 at com.sivalabs.homeautomation.useraccounts.LoginController.login(LoginController.java:51)

Here I have enabled the Annotation based configuration using <context:annotation-config/>.
I have configured the base package containing the Spring beans using <context:component-scan base-package="com.sivalabs"/>.
I have enabled the Annotation based Transaction Management using <tx:annotation-driven/> and @Transactional.

But still I am getting "No Hibernate Session bound to thread" Exception. Why?

Here is the reason:

In Spring reference documentation we can found the below mentioned important note:

"<tx:annotation-driven/> only looks for @Transactional on beans in the same application context it is defined in. This means that, if you put <tx:annotation-driven/> in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services."


So when my application is started first it loads the beans configured in dispatcher-servlet.xml and then look in applicationContext.xml. As i mentioned "com.sivalabs" as my base-package to scan for Spring beans my business services and DAOs which are annotated with @Service, @Repository will also be loaded by the container. Later when Spring tries to load beans from applicationContext.xml it won't load my services and DAOs as they are already loaded by parent ApplicaationContext. So the <tx:annotation-driven/> wont be applied for business services or DAOs annotated with @Transactional.

Solution1: If you are following package-by-layer approach:
Probably you may put all your controllers in one package say com.sivalabs.appname.web.controllers

Then change the <context:annotation-config/> configuration in dispatcher-servlet.xml as:
<context:component-scan base-package="com.sivalabs.appname.web.controllers"/>
With this only the controllers annotated with @Controller in com.sivalabs.appname.web.controllers package will be loaded by parent ApplicationContext and rest of the services, DAOs will be loaded by child ApplicationContext.

Solution2: If you are following package-by-feature approach:
If you follow the package-by-feature approach, you will put all the Controller, Service, DAOs related to one feature in one package.
With this the Controllers, Services, DAOs will be spanned across the packages.

Then change the <context:annotation-config/> configuration in dispatcher-servlet.xml as:

 <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>


With this only the controllers annotated with @Controller will be loaded by parent ApplicationContext.
And the Services, DAOs will be loaded by child ApplicationContext and <tx:annotation-driven/> will be applied.

Friday, April 1, 2011

SpringMVC3 Hibernate CRUD Sample Application

To learn any web framework starting with a HelloWorld application is a good idea. Once we get familiarity with the framework configuration it would be better to do a CRUD(Create,Read,Update,Delete) application which covers various aspects of a web framework like Validations, Request URL Mappings, Request Parameter Binding,
Pre-populating forms etc.

Now I am going to explain how to write a Simple CRUD application using SpringMVC3, Hibernate and MySQL.
Our Application is ContactsManagements where you can view or search contacts, create new contacts, edit or delete existing contacts.

Step#1: Create the CONTACTS Table

CREATE TABLE  CONTACTS 
(
  id int(10) unsigned NOT NULL AUTO_INCREMENT,
  name varchar(45) NOT NULL,
  address varchar(45) DEFAULT NULL,
  gender char(1) DEFAULT 'M',
  dob datetime DEFAULT NULL,
  email varchar(45) DEFAULT NULL,
  mobile varchar(15) DEFAULT NULL,
  phone varchar(15) DEFAULT NULL,
  PRIMARY KEY (id)
);

Step#2: Copy the SpringMVC, Hibernate and their dependent jars into WEB-INF/lib folder.
If you are using Maven you can mention the following dependencies.


  
    junit
    junit
    4.8.1
    jar
    compile
   
   
     org.springframework
     spring-web
     3.0.5.RELEASE
     jar
     compile
    
    
     org.springframework
     spring-core
     3.0.5.RELEASE
     jar
     compile
     
      
       commons-logging
       commons-logging
      
     
    
    
     log4j
     log4j
     1.2.14
     jar
     compile
    
    
     org.springframework
     spring-tx
     3.0.5.RELEASE
     jar
     compile
    
    
     jstl
     jstl
     1.1.2
     jar
     compile
    
    
     taglibs
     standard
     1.1.2
     jar
     compile
    
    
     org.springframework
     spring-webmvc
     3.0.5.RELEASE
     jar
     compile
    
    
     org.springframework
     spring-aop
     3.0.5.RELEASE
     jar
     compile
    
    
     commons-digester
     commons-digester
     2.1
     jar
     compile
    
    
     commons-collections
     commons-collections
     3.2.1
     jar
     compile
    
    
     org.hibernate
     hibernate-core
     3.3.2.GA
     jar
     compile
    
    
     javax.persistence
     persistence-api
     1.0
     jar
     compile
    
    
     c3p0
     c3p0
     0.9.1.2
     jar
     compile
    
    
     org.springframework
     spring-orm
     3.0.5.RELEASE
     jar
     compile
    
    
     org.slf4j
     slf4j-api
     1.6.1
     jar
     compile
    
    
     org.slf4j
     slf4j-log4j12
     1.6.1
     jar
     compile
    
    
     cglib
     cglib-nodep
     2.2
     jar
     compile
    
    
     org.hibernate
     hibernate-annotations
     3.4.0.GA
     jar
     compile
    
    
     jboss
     javassist
     3.7.ga
     jar
     compile
    
    
     mysql
     mysql-connector-java
     5.1.14
     jar
     compile
    
  

Step#3: Configure SpringMVC

a) Configure DispatcherServlet in web.xml

  dispatcher
  org.springframework.web.servlet.DispatcherServlet
  1
 
 
 
  dispatcher
  *.do
 

 
  org.springframework.web.context.ContextLoaderListener
 
 
     contextConfigLocationclasspath:applicationContext.xml
  

b) Configure View Resolver in WEB-INF/dispatcher-servlet.xml


 
 

c) Configure Annotation support, PropertyPlaceHolderConfigurer, ResourceBundleMessageSource in WEB-INF/classes/applicationContext.xml

 
 
 
   
 
 
 
    
 

Step#4: Configure JDBC connection parameters and Hibernate properties in config.properties

################### JDBC Configuration ##########################
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/sivalabs
jdbc.username=root
jdbc.password=admin

################### Hibernate Configuration ##########################
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
#hibernate.hbm2ddl.auto=update
hibernate.generate_statistics=true

Step#5: Configure DataSource, SessionFactory, TransactionManagement support in WEB-INF/classes/applicationContext.xml


   
 
 
     
     
               
             ${hibernate.dialect}          
             ${hibernate.show_sql}
        
     
  
 
  
  
    
 
 
 
    


Step#6: Configure the Labels, error messages in WEB-INF/classes/Messages.properties

App.Title=SivaLabs
typeMismatch.java.util.Date={0} is Invalid Date.
dob=DOB

Step#7: Create the Entity class Contact.java

package com.sivalabs.contacts;

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;

import org.apache.commons.lang.builder.ToStringBuilder;

@Entity
@Table(name="CONTACTS")
public class Contact
{
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private int id;
 @Column private String name;
 @Column private String address; 
 @Column private String gender; 
 @Column private Date dob; 
 @Column private String email;
 @Column private String mobile; 
 @Column private String phone;
 
 @Override
 public String toString()
 {
  return ToStringBuilder.reflectionToString(this);
 }
 //setters & getters 
}

Step#8: Create the ContactsDAO.java which performs CRUD operations on CONTACTS table.

package com.sivalabs.contacts;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Transactional
public class ContactsDAO
{
 @Autowired
 private SessionFactory sessionFactory;
 
 public Contact getById(int id)
 {
  return (Contact) sessionFactory.getCurrentSession().get(Contact.class, id);
 }
 
 @SuppressWarnings("unchecked")
 public List<Contact> searchContacts(String name)
 {
  Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Contact.class);
  criteria.add(Restrictions.ilike("name", name+"%"));
  return criteria.list();
 }
 
 @SuppressWarnings("unchecked")
 public List<Contact> getAllContacts()
 {
  Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Contact.class);
  return criteria.list();
 }
 
 public int save(Contact contact)
 {
  return (Integer) sessionFactory.getCurrentSession().save(contact);
 }
 
 public void update(Contact contact)
 {
  sessionFactory.getCurrentSession().merge(contact);
 }
 
 public void delete(int id)
 {
  Contact c = getById(id);
  sessionFactory.getCurrentSession().delete(c);
 }
}

Step#9: Create ContactFormValidator.java which performs the validations on saving/updating a contact.

package com.sivalabs.contacts;

import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

@Component("contactFormValidator")
public class ContactFormValidator implements Validator
{
 @SuppressWarnings("unchecked")
 @Override
 public boolean supports(Class clazz)
 {
  return Contact.class.isAssignableFrom(clazz);
 }

 @Override
 public void validate(Object model, Errors errors)
 {
  ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name","required.name", "Name is required.");
 }
}

Step#10: Create ContactsControllers.java which processes all the CRUD requests.

package com.sivalabs.contacts;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class ContactsControllers
{
 @Autowired
 private ContactsDAO contactsDAO;
 
 @Autowired
 private ContactFormValidator validator;
  
 @InitBinder
 public void initBinder(WebDataBinder binder) 
 {
  SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
  dateFormat.setLenient(false);
  binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
 }
  
 @RequestMapping("/searchContacts")
 public ModelAndView searchContacts(@RequestParam(required= false, defaultValue="") String name)
 {
  ModelAndView mav = new ModelAndView("showContacts");
  List<Contact> contacts = contactsDAO.searchContacts(name.trim());
  mav.addObject("SEARCH_CONTACTS_RESULTS_KEY", contacts);
  return mav;
 }
 
 @RequestMapping("/viewAllContacts")
 public ModelAndView getAllContacts()
 {
  ModelAndView mav = new ModelAndView("showContacts");
  List<Contact> contacts = contactsDAO.getAllContacts();
  mav.addObject("SEARCH_CONTACTS_RESULTS_KEY", contacts);
  return mav;
 }
 
 @RequestMapping(value="/saveContact", method=RequestMethod.GET)
 public ModelAndView newuserForm()
 {
  ModelAndView mav = new ModelAndView("newContact");
  Contact contact = new Contact();
  mav.getModelMap().put("newContact", contact);
  return mav;
 }
 
 @RequestMapping(value="/saveContact", method=RequestMethod.POST)
 public String create(@ModelAttribute("newContact")Contact contact, BindingResult result, SessionStatus status)
 {
  validator.validate(contact, result);
  if (result.hasErrors()) 
  {    
   return "newContact";
  }
  contactsDAO.save(contact);
  status.setComplete();
  return "redirect:viewAllContacts.do";
 }
 
 @RequestMapping(value="/updateContact", method=RequestMethod.GET)
 public ModelAndView edit(@RequestParam("id")Integer id)
 {
  ModelAndView mav = new ModelAndView("editContact");
  Contact contact = contactsDAO.getById(id);
  mav.addObject("editContact", contact);
  return mav;
 }
 
 @RequestMapping(value="/updateContact", method=RequestMethod.POST)
 public String update(@ModelAttribute("editContact") Contact contact, BindingResult result, SessionStatus status)
 {
  validator.validate(contact, result);
  if (result.hasErrors()) {
   return "editContact";
  }
  contactsDAO.update(contact);
  status.setComplete();
  return "redirect:viewAllContacts.do";
 }
  
 @RequestMapping("deleteContact")
 public ModelAndView delete(@RequestParam("id")Integer id)
 {
  ModelAndView mav = new ModelAndView("redirect:viewAllContacts.do");
  contactsDAO.delete(id);
  return mav;
 } 
}

Step#11: Instead of writing the JSTL tag library declerations in all the JSPs, declare them in one JSP and include that JSP in other JSPs.
taglib_includes.jsp

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>

Step#12: Create the JSPs.

a)showContacts.jsp
<%@include file="taglib_includes.jsp" %>

<html>
<head>

<title> </title>

</head>
<body style="font-family: Arial; font-size:smaller;">
 
Enter Contact Name
  
  
Id Name Address Mobile
No Results found

 Edit
  Delete
</body> </html>

b)newContact.jsp

<%@include file="taglib_includes.jsp" %>

<html>
<head>
 
 <title> </title>
</head>
<body style="font-family: Arial; font-size:smaller;">

Edit Contact Form


Name

DOB
Gender
Address
Email
Mobile


 

 
</body> </html>

a)editContact.jsp

<%@include file="taglib_includes.jsp" %>

<html>
<head>
 
 <title> </title>
</head>
<body style="font-family: Arial; font-size:smaller;">

Edit Contact Form


Id

Name

DOB
Gender
Address
Email
Mobile


 

 
</body> </html>

Step#13: Write the javascript file js/contacts.js containing the utility methods

function go(url)
{
 window.location = url;
}

function deleteContact(url)
{
 var isOK = confirm("Are you sure to delete?");
 if(isOK)
 {
  go(url);
 }
}
Step#14: The welcome file index.jsp
<%
response.sendRedirect("viewAllContacts.do");
%>

Step#15: Start the server and point your browser URL to http://localhost:8080/SpringMVCHibernate

You can download the source code at
SpringMVCHibernate.zip