Showing posts with label Spring. Show all posts
Showing posts with label Spring. Show all posts

Monday, January 25, 2016

Integrating JQGrid with Spring MVC and Gson

I was working on a single page application where i wanted to use the grid functionality in one part of the application which was using Spring MVC. It has been some time since i last used JQGrid and finding the information required to get me up and about was bit of a challenge. On this post, I wanted to collate all the information and put it into a tutorial to follow so anyone who might be using the same functionality might find it helpful to setup JQGrid.

First of all, we will setup a sample web project on Eclipse and define the web.xml as follows;


 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>JQGridExample</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  
  <servlet>
        <servlet-name>JQGridExample</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>JQGridExample</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
 
</web-app>

To wire up Spring MVC, I have registered the DispatcherServlet to be loaded on start-up. This is basically how you will register any Spring MVC application. Next up, we need to create the spring configuration to register the required components/elements of our spring MVC application.

In this instance, I have kept the spring context file name to the "servlet-name" given on my web.xml because by default when the spring container loads up, it will look for a file with the format <servletname>-servlet.xml

If you want to use any other name you want for your spring context configuration file, you can do so. You just need to register the context loader on your web.xml.

So let us see how our spring context configuration file looks like;


 
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 http://www.springframework.org/schema/mvc
 http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.0.xsd">
 
    <context:component-scan base-package="com.example.jqgrid.controller" />
     <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
    </bean>
    
    <mvc:resources mapping="/resources/**" location="/resources/"/>
    
    
    <mvc:annotation-driven/>
 
    
</beans>

We first register the package that contains all our controller classes. In this instance it will be just one controller. With the component-scan element, it will scan all classes under the "controller" package.

Next up, we tell the Spring container how to resolve our JSP files. In this instance the internal view resolver is being used and we provide the location of where our JSP files reside on the application.

The next interesting part on this configuration is the <mvc:resources> element. The reason to define this is to let the Spring container know about our static resources such as the javascript files, images, stylesheets. If we do not define them as resources, whenever you refer a javascript file for example in your application, spring mvc will try to match an existing controller by looking at the defined URL patterns. In this case, all my css, javascript,image files reside under the resources folder.

I then define the index.jsp which is the entry point into our application. Now I do not want to do anything on this page and i simply re-direct it to a different page which is resolved via spring-mvc. Our index.jsp file is as follows;


 
<script type="text/javascript">
 window.location.replace("jqGridExample");
</script>

I am simply re-directing the URL to jqGridExample. Now to understand how this is resolved from spring-mvc, we will need look at our controller class. Our controller class is as follows;


 
package com.example.jqgrid.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.example.jqgrid.common.util.JsonUtil;
import com.example.jqgrid.dto.JQGridDTO;
import com.example.jqgrid.dto.SuperHeroDTO;
import com.example.jqgrid.handler.JQGridHandler;

/**
 * This class acts as the controller for JQGrid related functionality.
 * 
 * @author Dinuka Arseculeratne
 * 
 */
@Controller
public class JQGridController {

 /**
  * This method will display the page used to display the grid.
  * 
  * @param req
  * @param res
  * @return
  */
 @RequestMapping(method = { RequestMethod.POST, RequestMethod.GET }, path = "/jqGridExample")
 public String jqGrid(HttpServletRequest req, HttpServletResponse res) {
  String forward = "jqgrid/jqGridData";

  return forward;
 }

 /**
  * This method will handle fetching data required for the JQGrid.
  * 
  * @param req
  * @param res
  * @return
  */
 @RequestMapping(method = { RequestMethod.POST, RequestMethod.GET }, path = "/loadData")
 public String loadData(HttpServletRequest req, HttpServletResponse res) {
  String forward = "common/formData";

  JQGridDTO<SuperHeroDTO> gridData = new JQGridHandler().loadSuperHeroes(req);
  req.setAttribute("formData", JsonUtil.toJsonObj(gridData));
  return forward;
 }

}



So if we look at the first method, you can see we are simply return a text called "jqgrid/jqGridData". Now to understand what this does, we need to go back and look at our spring context configuration file. In that we specified that all our JSP files reside in the "WEB-INF/jsp" folder and the suffix is ".jsp". So in this instance the path we return from this method tells the spring container that the JSP to be returned is in fact in "WEB-INF/jsp/jqgrid/jqGridData.jsp". Note that we did not need to specify the suffix as ".jsp" because we already configured that on our spring context configuration.

We will come back to the second method after we look at our page where we have defined the JQGrid. The jqGridData.jsp is as follows;


 
<!DOCTYPE html>
<html>
 <head>
  <title>JQGrid Example</title>

   
    <link href="resources/css/jquery-ui.css" rel="stylesheet">
    <link href="resources/css/jquery-ui.theme.css" rel="stylesheet">
    <link href="resources/css/jquery-ui.structure.min.css" rel="stylesheet">
    <link rel="stylesheet" href="resources/css/ui.jqgrid.css">
    
 </head>
 
<body>

<div>
 
   <table id="list">
                <tr>
                        <td />
                </tr>
        </table>
        <div id="pager"></div>
        <div style="margin-top:10px;">
        <input type="button" id="showSelected" value="Show Selected"/>
        </div>
 
 
</div>

  <script src="resources/js/jquery-1.11.1.min.js"></script>
  <script src="resources/js/jquery-ui.min.js"></script>
  <script src="resources/js/i18n/grid.locale-en.js"></script>
  <script src="resources/js/jquery.jqGrid.min.js"></script>
  
  
<script type="text/javascript">

 $(document).ready(function(){
  $("#list").jqGrid({
                url : "loadData",
                datatype : "json",
                mtype : 'POST',
                colNames : [ 'Name','Alias','Super Power'],
                colModel : [ {
                        name : 'name',
                        index : 'name',
                        width : 150
                }, {
                        name : 'alias',
                        index : 'alias',
                        width : 150,
                        editable : false
                }, {
                        name : 'power',
                        index : 'power',
                        width : 550,
                        editable : false
                }],
                pager : '#pager',
                rowNum : 10,
                height: 'auto',
                rowList : [ 10 ],
                sortname : 'invid',
                sortorder : 'desc',
                viewrecords : true,
                gridview : true,
                multiselect: true,
            multiboxonly: false,
                caption : 'Super Heroes',
                jsonReader : {
                        repeatitems : false,
                }
        });
        jQuery("#list").jqGrid('navGrid', '#pager', {
                edit : false,
                add : false,
                del : false,
                search : false
        });
        
        
        $('#showSelected').on('click',function(){
         
         var selRowArr = jQuery("#list").getGridParam('selarrrow');
         var selectedAppIds = [];
         for(var i=0;i<selRowArr.length;i++){
          var celValue =  $('#list').jqGrid('getCell', selRowArr[i], 'alias');
          selectedAppIds.push(celValue);
         }
         alert(selectedAppIds);
         $('#list').trigger( 'reloadGrid' );
         
   
        });
 
 });
</script>

</body>
</html>

First of all, we need to define the element on which the JQGrid will be loaded. In this instance that is the HTML table element with the id of  "list". And since we want the pagination ability, we define our pagination section below the grid. In this instance, the pagination section is defined with the div with the id of "pager".

We then look at the java script code as the bottom. Here we load the JQGrid by calling the method jqGrid() passing in the required attributes. I will not be explaining all the attributes defined here as there are many more which i have not used in this instance. The most relevant attributes for this tutorial will be explained. So first off, the URL. This is defined as "loadData". We need to go back our controller class to understand how this is mapped.

On the controller, we have defined the second method as "loadData" which fetches the data required for the grid. Now the interesting part is, JQGrid expects the data sent across in a particular format. To adhere to this format, i have defined a class to hold this structure which is defined as JQGridDTO. Let us see how that class looks like;


 
package com.example.jqgrid.dto;

import java.io.Serializable;
import java.util.List;

/**
 * This class acts as common template for all pages that use the JQGrid.
 * 
 * @author Dinuka Arseculeratne
 * 
 * @param <T>
 */
public class JQGridDTO < T extends Serializable > {

    private int page;

    private String total;

    private String records;

    private List<T> rows;

    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        this.page = page;
    }

    public String getTotal() {
        return total;
    }

    public void setTotal(String total) {
        this.total = total;
    }

    public String getRecords() {
        return records;
    }

    public void setRecords(String records) {
        this.records = records;
    }

    public List<T> getRows() {
        return rows;
    }

    public void setRows(List<T> rows) {
        this.rows = rows;
    }

}


This is the structure of the data required by JQGrid. I have kept the rows data structure generic in order to be able to use this same class to pass different types of data to the grid as required. It can be any type of object as long as it implements the Serializable interface.

So I am a big time super heroes fan, and hence in this instance I will be displaying some information on some of the super heroes. I have included super heroes from both the DC and Marvel universe to keep everyone happy.

So let us look at our data object and the handler class which will load our data;

 
package com.example.jqgrid.dto;

import java.io.Serializable;

/**
 * 
 * @author Dinuka Arseculeratne
 *
 */
public class SuperHeroDTO implements Serializable {

 /**
  * 
  */
 private static final long serialVersionUID = 1420635747715993129L;

 private String name;
 private String alias;
 private String power;

 public SuperHeroDTO(String name, String alias, String power) {
  this.name = name;
  this.alias = alias;
  this.power = power;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public String getAlias() {
  return alias;
 }

 public void setAlias(String alias) {
  this.alias = alias;
 }

 public String getPower() {
  return power;
 }

 public void setPower(String power) {
  this.power = power;
 }

}



 
package com.example.jqgrid.handler;

import java.util.LinkedList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import com.example.jqgrid.dto.JQGridDTO;
import com.example.jqgrid.dto.SuperHeroDTO;

/**
 * The handler class used to fetch the data required.
 * 
 * @author Dinuka Arseculeratne
 *
 */
public class JQGridHandler {

 /**
  * This method will fetch the super hero list. Of course i have mixed and
  * matched DC and Marvel in order to keep peace on the universe.
  * 
  * @return
  */
 public JQGridDTO<SuperHeroDTO> loadSuperHeroes(final HttpServletRequest req) {
  /**
   * The page and rows are sent from the JQGrid component with the Ajax
   * query.
   * 
   */
  int page = Integer.valueOf(req.getParameter("page")).intValue();
  int pageSize = Integer.valueOf(req.getParameter("rows")).intValue();

  /**
   * I am not using the star index and end index in this case, but in an
   * ideal situation, you will be passing the start and end index to your
   * pagination SQL query.
   * 
   */
  int startIndex = page == 1 ? 0 : (pageSize * (page - 1));
  int endIndex = page == 1 ? pageSize : pageSize * page;
  int total = -1;

  JQGridDTO<SuperHeroDTO> jqGridData = new JQGridDTO<SuperHeroDTO>();
  List<SuperHeroDTO> superHeroList = new LinkedList<SuperHeroDTO>();
  SuperHeroDTO flash = new SuperHeroDTO("Barry Allen", "Flash", "Super speed, Taping into the speed force");
  superHeroList.add(flash);

  SuperHeroDTO superMan = new SuperHeroDTO("Clark Kent", "Superman", "Flying, super speed");
  superHeroList.add(superMan);

  SuperHeroDTO batman = new SuperHeroDTO("Bruce Wayne", "Batman", "Cool toys, Intelligence");
  superHeroList.add(batman);

  SuperHeroDTO professorX = new SuperHeroDTO("Professor Xavier", "Professor X", "Mind control");
  superHeroList.add(professorX);

  /**
   * The total in the ideal situation would be the count of the records of
   * your SQL query from the table you want to fetch data from.
   * 
   */
  total = superHeroList.size();

  jqGridData.setPage(page);
  jqGridData.setTotal(String.valueOf(Math.ceil((double) total / pageSize)));
  jqGridData.setRecords(String.valueOf(total));
  jqGridData.setRows(superHeroList);
  return jqGridData;
 }
}



Typically you will be using a database to fetch your data. To maintain the brevity of this tutorial i have just loaded up static data. On the code comments I have mentioned how you would be passing the data when using an actual database.

In this instance, the JQGrid is setup to receive the data in JSON format. So to convert our super hero object to its JSON equivalent, i have used Google's GSON library. I wrote a helper class to convert JSON objects to Java objects and Java objects to JSON objects which I have shared in one of my previous articles which you can find here.

I have not used the spring-mvc default functionality to send a JSON response. In this example what I do is set the JSON output in a request attribute and then forward the page to a common page where it just prints out that attribute and the response is sent back on the Ajax request made by the JQGrid component. This common page is defined as follows;


 
<%=request.getAttribute("formData")%>


Going back to our JSP file which defined the JQGrid, the next important attribute I want to focus on is the "colModel". This maps the data sent on your JSON output to the grid columns that are displayed. In this instance you can see the names mentioned here are the instance variable names defined on our super hero data object. The rest of the attributes are self-explanatory so I will not delve into the details on those attributes.

Another important use case I required was to be able to send the selected rows to the back-end. To do this, you can use the in-built JQGrid functions. The following code shows the code which retrieves the name of the super hero on all selected rows (in this case as the multi select feature is enabled on the grid) and puts it into a Java script array.


 
 $('#showSelected').on('click',function(){
         
         var selRowArr = jQuery("#list").getGridParam('selarrrow');
         var selectedAppIds = [];
         for(var i=0;i<selRowArr.length;i++){
          var celValue =  $('#list').jqGrid('getCell', selRowArr[i], 'alias');
          selectedAppIds.push(celValue);
         }
         alert(selectedAppIds);
         $('#list').trigger( 'reloadGrid' );
         
   
        });

And that ends by tutorial on how to setup JQGrid with Spring MVC and Gson. The working code is checked into my GIT repository and can be found here. You can clone the repository if required and run the application.

Monday, November 26, 2012

How cool is integration testing with Spring+Hibernate

I am guilty of not writing integration testing (At least for database related transactions) up until now. So in order to eradicate the guilt i read up on how one can achieve this with minimal effort during the weekend. Came up with a small example depicting how to achieve this with ease using Spring and Hibernate. With integration testing, you can test your DAO(Data access object) layer without ever having to deploy the application. For me this is a huge plus since now i can even test my criteria's, named queries and the sort without having to run the application.

There is a property in hibernate that allows you to specify an sql script to run when the Session factory is initialized. With this, i can now populate tables with data that required by my DAO layer. The property is as follows;


 <prop key="hibernate.hbm2ddl.import_files">import.sql</prop>

According to the hibernate documentation, you can have many comma separated sql scripts.One gotcha here is that you cannot create tables using the script. Because the schema needs to be created first in order for the script to run. Even if you issue a create table statement within the script, this is ignored when executing the script as i saw it.

Let me first show you the DAO class i am going to test;


 package com.unittest.session.example1.dao;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.unittest.session.example1.domain.Employee;

@Transactional(propagation = Propagation.REQUIRED)
public interface EmployeeDAO {

 public Long createEmployee(Employee emp);
 
 public Employee getEmployeeById(Long id);
}



package com.unittest.session.example1.dao.hibernate;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.unittest.session.example1.dao.EmployeeDAO;
import com.unittest.session.example1.domain.Employee;

public class EmployeeHibernateDAOImpl extends HibernateDaoSupport implements
  EmployeeDAO {

 @Override
 public Long createEmployee(Employee emp) {
  getHibernateTemplate().persist(emp);
  return emp.getEmpId();
 }

 public Employee getEmployeeById(Long id) {
  return getHibernateTemplate().get(Employee.class, id);
 }
}

Nothing major, just a simple DAO with two methods where one is to persist and one is to retrieve. For me to test the retrieval method i need to populate the Employee table with some data. This is where the import sql script which was explained before comes into play. The import.sql file is as follows;



 insert into Employee (empId,emp_name) values (1,'Emp test');

This is just a basic script in which i am inserting one record to the employee table. Note again here that the employee table should be created through the hibernate auto create DDL option in order for the sql script to run. More info can be found here. Also the import.sql script in my instance is within the classpath. This is required in order for it to be picked up to be executed when the Session factory is created.

Next up let us see how easy it is to run integration tests with Spring.


 package com.unittest.session.example1.dao.hibernate;

import static org.junit.Assert.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;

import com.unittest.session.example1.dao.EmployeeDAO;
import com.unittest.session.example1.domain.Employee;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:spring-context.xml")
@TransactionConfiguration(defaultRollback=true,transactionManager="transactionManager")
public class EmployeeHibernateDAOImplTest {

 @Autowired
 private EmployeeDAO employeeDAO;
 
 @Test
 public void testGetEmployeeById() {
  Employee emp = employeeDAO.getEmployeeById(1L);
  
  assertNotNull(emp);
 }
 
 @Test
 public void testCreateEmployee()
 {
  Employee emp = new Employee();
  emp.setName("Emp123");
  Long key = employeeDAO.createEmployee(emp);
  
  assertEquals(2L, key.longValue());
 }

}


A few things to note here is that you need to instruct to run the test within a Spring context. We use the SpringJUnit4ClassRunner for this. Also the transction attribute is set to defaultRollback=true. Note that with MySQL, for this to work, your tables must have the InnoDB engine set as the MyISAM engine does not support transactions.

And finally i present the spring configuration which wires everything up;


 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="  
          http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd  
          http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd  
          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">


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

 <tx:annotation-driven />

 <bean id="sessionFactory"
  class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
  <property name="packagesToScan">
   <list>
    <value>com.unittest.session.example1.**.*</value>
   </list>
  </property>
  <property name="hibernateProperties">
   <props>
    <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
    <prop key="hibernate.connection.driver_class">com.mysql.jdbc.Driver</prop>
    <prop key="hibernate.connection.url">jdbc:mysql://localhost:3306/hbmex1</prop>
    <prop key="hibernate.connection.username">root</prop>
    <prop key="hibernate.connection.password">password</prop>
    <prop key="hibernate.show_sql">true</prop>
    <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
    <!-- -->
    <prop key="hibernate.hbm2ddl.auto">create</prop>
    <prop key="hibernate.hbm2ddl.import_files">import.sql</prop>
   </props>
  </property>
 </bean>

 <bean id="empDAO"
  class="com.unittest.session.example1.dao.hibernate.EmployeeHibernateDAOImpl">
  <property name="sessionFactory" ref="sessionFactory" />
 </bean>

 <bean id="transactionManager"
  class="org.springframework.orm.hibernate3.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory" />
 </bean>

</beans>

That is about it. Personally i would much rather use a more light weight in-memory database such as hsqldb in order to run my integration tests.

Here is the eclipse project for anyone who would like to run the program and try it out.


Wednesday, December 1, 2010

Plugin Based Architecture With Spring Integration

Introduction :

                                The purpose of this article is to demonstrate that it is possible to achieve a pluggable architecture using Spring Integration and the patterns it supports. If i were to give an introduction to Spring Integration it is a fairly new addition to the spring's solutions suite. It implements most of the Enterprise Integration Patterns currently known which makes it easier for developers as they do not need to re-invent the wheel. Some of the solutions provided by Spring Integration are as follows;

  1. Router
  2. Transformer
  3. Gateway
  4. Splitter
There are many more. As i am just getting my feet wet with Spring integration this is all i have covered up to now.

Pre-requisites :
 In order to run this example you need the following jar files;
  1. com.springsource.org.aopalliance-1.0.0.jar
  2. commons-logging-1.1.1.jar
  3. spring-aop-3.0.3.RELEASE.jar
  4. spring-asm-3.0.3.RELEASE.jar
  5. spring-beans-3.0.3.RELEASE.jar
  6. spring-context-3.0.3.RELEASE.jar
  7. spring-context-3.0.5.RELEASE.jar
  8. spring-context-support-3.0.3.RELEASE.jar
  9. spring-core-3.0.3.RELEASE.jar
  10. spring-expression-3.0.3.RELEASE.jar
  11. spring-tx-3.0.3.RELEASE.jar
  12. spring-integration-core-2.0.0.RC2.jar 

Note that i have used Spring 3.0.3 for this project. If you are using Spring 2.0 the required jars will be less. But as i used Spring Integration 2.0 i wanted to go with Spring 3.0.

Proposed Solution :
I have used the banking domain to demonstrate my example. The solution is to develop a system which will allows you to make payments to any banking system. The architecture is such that all code interfacing to any banking system is developed independently which can later be integrated to the main application as an when required. And you just have to inject the respective spring-integration config xml along with the plugin developed which can be injected to the project. 

In this solution i have done it in the same code base but in real life the plugin development should be in a different module.

Implmentation :
First let me give you an overview diagram of the proposed solution;

   

As you can see this is a typical architecture for a j2EE project. The controller i have specified here can be anything from struts to JSF to Spring MVC. The Service layer is basically the Spring layer which the controller will mainly be in contact with.

The main point to note is the spring integration layer. This is what injects all the plugins in the plugin repository. Next i will explain in detail the patterns of spring integration used in the solution. The following digram clearly explains this;


I will not go into detail on this digram as the diagram it self is self explanatory. So now lets get our hands dirty with some code;

First off i will start with the service layer;

package com.paymentgateway.services;

import com.paymentgateway.dto.PaymentRequestDTO;
import com.paymentgateway.dto.PaymentResponseDTO;

/**
 * The service interface is what the client from our application interacts with
 * the client is not aware of spring integration being used.
 * 
 * @author dinuka
 */
public interface PaymentService {

    public PaymentResponseDTO makePayment(PaymentRequestDTO paymentRequestDTO);

}


package com.paymentgateway.services;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.message.GenericMessage;
import org.springframework.stereotype.Component;

import com.paymentgateway.dto.PaymentRequestDTO;
import com.paymentgateway.dto.PaymentResponseDTO;
import com.paymentgateway.dto.PaymentStatusCode;
import com.paymentgateway.dto.SystemActions;
import com.paymentgateway.gateway.CentralPaymentGateway;

@Component("paymentService")
public class PaymentServiceImpl implements PaymentService {

    @Autowired
    private CentralPaymentGateway gateway;

    @Override
    public PaymentResponseDTO makePayment(PaymentRequestDTO paymentRequestDTO) {
        /**
         * Here you can do any validation checks for null values if you need
         * and throw any relevant exception as needed. For simplicity purposes
         * i have not done so here.
         */

        /**
         * In the header we specify the banking system this message needs to be routed to<br>
         * Then in the
         */
        Map headerMap = new HashMap();
        headerMap.put("BANKING_SYSTEM", paymentRequestDTO.getBankingSystem());
        headerMap.put("ACTION", SystemActions.PAYMENT.toString());
        GenericMessage<PaymentRequestDTO> paymentRequestMsg = new GenericMessage<PaymentRequestDTO>(paymentRequestDTO,
                headerMap);
        PaymentResponseDTO paymentResponseDTO = gateway.makePayment(paymentRequestMsg);

        if (paymentResponseDTO.getStatusCode() == PaymentStatusCode.FAILURE) {
            /**
             * Throw relevant exception
             */
        }
        return paymentResponseDTO;

    }

}


And the DTOs used are as follows;



package com.paymentgateway.dto;

import java.io.Serializable;

/**
 * This DTO holds the data that needs to be passed to the
 * relevant plugin in order to make a payment
 * 
 * @author dinuka
 */
public class PaymentRequestDTO implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 582470760696219645L;

    /**
     * The account number of the customer
     */
    private String accountNumber;

    /**
     * The amount needed to be reduced
     */
    private Double deductAmount;

    /**
     * The First Name of the customer
     */
    private String firstName;

    /**
     * The Last Name of the customer
     */
    private String lastName;

    /**
     * This should ideally be moved to a CommonDTO as this will be reused by all
     * subsequent DTOs. Default banking system is "abc". The client needs to set
     * which banking system is needed to connect to.
     */
    private String bankingSystem = "abc";

    public String getAccountNumber() {
        return accountNumber;
    }

    public void setAccountNumber(String accountNumber) {
        this.accountNumber = accountNumber;
    }

    public Double getDeductAmount() {
        return deductAmount;
    }

    public void setDeductAmount(Double deductAmount) {
        this.deductAmount = deductAmount;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getBankingSystem() {
        return bankingSystem;
    }

    public void setBankingSystem(String bankingSystem) {
        this.bankingSystem = bankingSystem;
    }

    @Override
    public String toString() {
        return "PaymentRequestDTO [accountNumber=" + accountNumber + ", deductAmount=" + deductAmount + ", firstName="
                + firstName + ", lastName=" + lastName + "]";
    }

}


package com.paymentgateway.dto;

import java.io.Serializable;

/**
 * This is the default payment response DTO that every plugin
 * must return back to the system
 * 
 * @author dinuka
 */
public class PaymentResponseDTO implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 2773607380706313950L;

    /**
     * The account number of the customer
     */
    private String accountNumber;

    /**
     * The first name of the customer
     */
    private String firstName;

    /**
     * The last name of the customer
     */
    private String lastName;

    /**
     * The remaining balance in the account of the customer
     */
    private Double availableBalance;

    /**
     * The balance reduced from the customer account
     */
    private Double reducedBalance;

    /**
     * The status code indicating whether the transaction was a success or not
     */
    private PaymentStatusCode statusCode = PaymentStatusCode.SUCCESS;

    /**
     * The transaction id assigned to the relevant transaction
     */
    private Long transationId;

    public String getAccountNumber() {
        return accountNumber;
    }

    public void setAccountNumber(String accountNumber) {
        this.accountNumber = accountNumber;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Double getAvailableBalance() {
        return availableBalance;
    }

    public void setAvailableBalance(Double availableBalance) {
        this.availableBalance = availableBalance;
    }

    public Double getReducedBalance() {
        return reducedBalance;
    }

    public void setReducedBalance(Double reducedBalance) {
        this.reducedBalance = reducedBalance;
    }

    public PaymentStatusCode getStatusCode() {
        return statusCode;
    }

    public void setStatusCode(PaymentStatusCode statusCode) {
        this.statusCode = statusCode;
    }

    public Long getTransationId() {
        return transationId;
    }

    public void setTransationId(Long transationId) {
        this.transationId = transationId;
    }

    @Override
    public String toString() {
        return "PaymentResponseDTO [accountNumber=" + accountNumber + ", firstName=" + firstName + ", lastName="
                + lastName + ", availableBalance=" + availableBalance + ", reducedBalance=" + reducedBalance
                + ", statusCode=" + statusCode + ", transationId=" + transationId + "]";
    }

}



package com.paymentgateway.dto;

/**
 * The status codes returned from each plugin indicating
 * if the transaction was a success or not
 * 
 * @author dinuka
 */
public enum PaymentStatusCode {

    SUCCESS, FAILURE
}



package com.paymentgateway.dto;

import com.paymentgateway.util.PaymentRouter;

/**
 * This enum defines the system wide actions
 * We use this name in our {@link PaymentRouter}
 * to decide which channel to route the message
 * 
 * @author dinuka
 */
public enum SystemActions {

    PAYMENT {
        @Override
        public String toString() {

            return "Payment";
        }
    }
}



Those are the DTOs i have used. Moving on, as the second diagram above specified we have defined a Central Gateway & A Router. So lets see how we have implemented those using spring integration;

package com.paymentgateway.gateway;

import org.springframework.integration.message.GenericMessage;

import com.paymentgateway.dto.PaymentRequestDTO;
import com.paymentgateway.dto.PaymentResponseDTO;

/**
 * This interface represents the common gateway which
 * will be used by Spring Integration to wire up the plugins
 * and also will be the central and first point of contact
 * by any client calling our business layer
 * 
 * @author dinuka
 */
public interface CentralPaymentGateway {

    /**
     * This method takes a parameter type of {@link GenericMessage} which wraps&lt;br&gt;
     * an instance of {@link PaymentRequestDTO}. Usage of sending an instance of&lt;br&gt;
     * Generic Message is so that we can add header values which can indicate&lt;br&gt;
     * which banking system to call to
     * 
     * @param paymentRequestDTO
     * @return
     */
    public PaymentResponseDTO makePayment(GenericMessage&lt;PaymentRequestDTO&gt; paymentRequestDTO);
}

Note that the gateway is just an interface defining our input parameters. We have used the GenericMessage defined by Spring integration. If you go back to the service layer implementation you can see that we have populated an instance of GenericMessage with the relevant DTO which is passed onto the gateway. The gateway here acts as a mediation layer.

Moving on with the Router implementation;

package com.paymentgateway.util;

import org.springframework.integration.Message;

/**
 * This is the base Router for All payment related functions
 * We route the message based on the banking system and the action
 * which comes in the header of the message. Ofcourse we can enhance this
 * to put the message on an error queue if the {@link Message} does not have the
 * relevant header values.
 * 
 * @author dinuka
 */
public class PaymentRouter {

    public String resolveBankChannel(Message message) {
        return (String) message.getHeaders().get("BANKING_SYSTEM") + (String) message.getHeaders().get("ACTION")
                + "Channel";
    }
}


Again if you go back to the PaymentServiceImpl class you can see we set the two headers BANKING_SYSTEM and ACTION. The router decides which channel this message should go on. You can see this in the next section when we wire up all this together.

The Spring configurations are as follows;

First off i present to you the main config file named context-config.xml. This mainly injects the service layer beans.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

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


Next we look at the core configuration where we wire up the Spring Integration related components;

spring-integration-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.0.xsd">

 <!-- The generic input channel which would be used to pass through all messages 
  coming into the Central Gateway -->
 <int:channel id="inputChannel"></int:channel>

 <!-- Here we wire up the Central Gateway which is the central point of access 
  from our service layer -->
 <int:gateway id="gateway" default-request-channel="inputChannel"
  service-interface="com.paymentgateway.gateway.CentralPaymentGateway"
  default-reply-channel="outputChannel"></int:gateway>



 <!-- This is the generic Output channel which will be used by to send the 
  output from any plugin. -->
 <int:channel id="outputChannel"></int:channel>

 <!-- The router is the one who decides which channel to send the message 
  passed in from input channel into. The client should send the name of the 
  Banking system where by 'SearchChannel' keyword is appended by the defaultRouter 
  bean. -->
 <int:router id="centralRouter" ref="defaultRouter" method="resolveBankChannel"
  input-channel="inputChannel"></int:router>

 <bean id="defaultRouter" name="defaultRouter"
  class="com.paymentgateway.util.PaymentRouter" />

 
 
</beans>


That is the core configuration which wires up the Gateway, Router and defines the Channels required by the application. Next off lets go into our plugin( of many plugins to come) the ABC Bank Plugin.



First we define the Base plugin interface which all plugin developers should adhere to;


package com.paymentgateway.plugins;

import com.paymentgateway.dto.PaymentRequestDTO;
import com.paymentgateway.dto.PaymentResponseDTO;

/**
 * This is the base plugin interface. All plugin developers should adhere to<br>
 * this interface when they write new plugins connecting to different banking<br>
 * systems.
 * 
 * @author dinuka
 */
public interface BasePlugin {

    public PaymentResponseDTO makePayment(PaymentRequestDTO paymentRequestDTO);

}


And the implementation of this interface is as follows;

package com.paymentgateway.plugins;

import com.paymentgateway.dto.PaymentRequestDTO;
import com.paymentgateway.dto.PaymentResponseDTO;
import com.paymentgateway.dto.PaymentStatusCode;

/**
 * This is the plugin used to connect to the ABC banking system
 * in order to do the payment transaction.
 * 
 * @author dinuka
 */
public class ABCBankPlugin implements BasePlugin {

    @Override
    /**
     * Right now we just return a mock value. But when the true implementation
     * comes you will deal with any connection rellated information
     * at this point.
     */
    public PaymentResponseDTO makePayment(PaymentRequestDTO paymentRequestDTO) {
        PaymentResponseDTO paymentResponseDTO = new PaymentResponseDTO();
        paymentResponseDTO.setAccountNumber("abc123");
        paymentResponseDTO.setAvailableBalance(10000d);
        paymentResponseDTO.setFirstName("Dinuka");
        paymentResponseDTO.setLastName("Arseculeratne");
        paymentResponseDTO.setReducedBalance(500d);
        paymentResponseDTO.setStatusCode(PaymentStatusCode.SUCCESS);
        paymentResponseDTO.setTransationId(1233424234l);
        return paymentResponseDTO;
    }

}


As this is just a mock implementation i have just returned the response DTO with values filled. Now that we have developed our plugin lets wire it up;



abc_bank_plugin-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.0.xsd">

 <!-- Start of ABC Banking System Plugin Injection -->

 <!-- This is the payment channel used for the ABC banking system -->
 <int:channel id="abcPaymentChannel"></int:channel>

 <!-- Wire up the ABC Banking plugin -->
 <bean id="abcBakingSysPlugin" name="abcBakingSysPlugin"
  class="com.paymentgateway.plugins.ABCBankPlugin" />

 <!-- This service activator is used to handle the payment response from 
  ABC banking system -->
 <int:service-activator input-channel="abcPaymentChannel"
  ref="abcBakingSysPlugin" method="makePayment" output-channel="outputChannel"></int:service-activator>

 <!-- End of ABC Banking System Plugin Injection -->
</beans>

And lastly i present a test class just so that you can run the solution given above;

package com.paymentgateway.test;

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

import com.paymentgateway.dto.PaymentRequestDTO;
import com.paymentgateway.dto.PaymentResponseDTO;
import com.paymentgateway.services.PaymentService;

/**
 * This is a test class showing how it all comes together
 * 
 * @author dinuka
 */
public class TestBankingApp {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("context-config.xml",
                "spring-integration-config.xml","abc_bank_plugin-config.xml");

        PaymentService paymentService = (PaymentService) context.getBean("paymentService");

        PaymentRequestDTO paymentRequestDTO = new PaymentRequestDTO();
        PaymentResponseDTO paymentResponseDTO = paymentService.makePayment(paymentRequestDTO);

        /**
         * We just print out the resulting DTO returned from the plugin<br>
         * as this is just a tutorial
         */
        System.out.println(paymentResponseDTO);
    }
}


Thats it. Your done with your plugin architecture. If you ever do develop another plugin all you have to do is implement the BasePlugin Interface and as well as give the wiring up spring file. The following diagram explains the flow in which the message travels which will give you an even clearer picture of what we have accomplished;


Future Enhancements:
  1. Implement a transformer pattern which will do the conversion of DTOs to application specific DTOs.
  2. Introduce an error channel where any error populated will be put in to. 

Thats it guys. Your comments and suggestions are most welcome.

References:

[1] http://static.springsource.org/spring-integration/docs/2.0.0.RELEASE/reference/htmlsingle/

Wednesday, June 16, 2010

Defining Custom Editors With Spring

Custom editors gives you a lot of flexibility and reduces XML configuration when defining your spring beans. Say for example i have the following Person object;


public class Person {

private String firstName;

private String lastName;

private int age;

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}


}


And the following Class called PersonManager is using this Person object as follows;


public class PersonManager {

private Person person;

public Person getPerson() {
return person;
}

public void setPerson(Person person) {
this.person = person;
}


}


If you wanted to inject a person object to the PersonManager class then you would first register the Person class as a spring bean and register that bean as a ref bean of PersonManager class.

But spring offers an easy way of injecting the Person object to the PersonManager by use of Custom PropertyEditors. With this you can define your values as a string value and create the Person object as you deem appropriate from the format you define. In my example i have defined the format to be;
firstname,lastname,age
hence is would be comma separated values which defined the values needed to create the Person object. Now in order to let spring understand how to handle this string value you need to define your own propertye editor. It is as follows;






public class PersonPropertyEditor extends PropertyEditorSupport{

@Override
public void setAsText(String arg0) throws IllegalArgumentException {

String[]vals = arg0.split(",");
Person p = new Person();
p.setFirstName(vals[0]);
p.setLastName(vals[1]);
p.setAge(Integer.valueOf(vals[2]));
setValue(p);
}
}



Here i simply split the string value and set the relevant values of the Person object and then call the setValue inherited method to set the value. Its as simple as that.

And finally you define your customer registar which binds your customer editor.


public class PersonConfiguratorWithRegistars implements PropertyEditorRegistrar {
@Override
public void registerCustomEditors(PropertyEditorRegistry arg0) {
arg0.registerCustomEditor(Person.class, new PersonPropertyEditor());

}
}



Now when letting spring know about your custom editor there were two ways initially before Spring 3.0. They are;

  1. Define as a customEditors property within org.springframework.beans.factory.config.CustomEditorConfigurer
  2. Define as a propertyEditorRegistrars within org.springframework.beans.factory.config.CustomEditorConfigurer
As of Spring 3.0 the customerEditors property is deprecated as they had a thread locking issue as explained here.

So lastly i show you how to wire your new customer editor and the PersonManager object by providing a string value. The application context XML is as follows;






<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

<!--

This is the OLD way of wiring your custom editor which is not thread safe

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="Person">
<bean id="personEditor" class="PersonPropertyEditor">
</bean>
</entry>
</map>
</property>
</bean>

-->

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<ref bean="customPersonPropertyEditor" />
</list>
</property>
</bean>

<bean id="customPersonPropertyEditor"
class="PersonConfiguratorWithRegistars" />

<bean id="perMgt" class="PersonManager">
<property name="person" value="John,Alan,23" />
</bean>


</beans>



Thats it. You can use the following test class to test the same;


public class PropertyEditorTest {

/**
* @param args
*/
public static void main(String[] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext("appContext.xml");
PersonManager personMgr = (PersonManager)appContext.getBean("perMgt");
Person p = personMgr.getPerson();
System.out.println(p.getFirstName()+" "+p.getLastName()+" "+p.getAge());
}

}

Friday, May 21, 2010

Spring - How to use Component and Autowired

Just put together a sample which made me understand how to use the above mentioned annotations defined by Spring hence thought i should blog about the same.

First lets take a look at the two classes that are exposed as spring beans.





package chapter3;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("calculator")
public class Calculator {
private Adder adder;

@Autowired
public void setAdder(Adder adder) {
this.adder = adder;
}

public void makeAnOperation(){
int r1 = adder.add(1,2);
System.out.println("r1 = " + r1);
}
}




package chapter3;

import org.springframework.stereotype.Component;

@Component("adder")
public class Adder {
public int add(int a, int b){
return a + b;
}
}

Few pointers to note here are as follows;

  • By annotation the class with @Component you tell the Spring container that these beans are needed to be instantiated and managed by the Spring container. This reduces XML configurations required because you do not need to manually edit the XML file entering bean definitions to each and every bean.
  • The @Autowired element binds an instance of the Adder class when the Spring container scans the Calculator class.
Next we look at the application context XML


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

<context:component-scan base-package="chapter3"/>
<context:annotation-config/>

</beans>


And finally to run the sample following is the main class;



package chapter3;

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

public class ComponentCheck {

public static void main(String[] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext(
"chapter3AppXML.xml");
Calculator calculator = (Calculator) appContext.getBean("calculator");
calculator.makeAnOperation();

}

}

Tuesday, September 29, 2009

Spring Mail API Wrapper

Recently it was needed at my working place to have a module to send SMTP mails. I found out that Spring provides a nice wrapper around the Java Mail API so you do not need to deal with boilerplate code. Hence after a few hours of Googling and coding I was able to come up with an API which sends mail using Spring. Following I give you the code snippets required.


package com.test.commons.mailservices.core.remoting.ejb.service;

import com.test.commons.mailservices.core.exceptions.MailSenderException;

public interface MailSenderService {

/**
* This method sends the mail to multiple recipients with the given subject
* @param mailMsg The message needed to be send as plain text
* @param recipientAddresses The mail addresses in an array to which the mail has to be sent
* @param subject The subject of the mail to be sent
* @throws MailSenderException this exception wraps the MailException throw by the Spring framework
*/
public void sendMessage(String mailMsg,String[] recipientAddresses,String subject)throws MailSenderException;

/**
* This method sends the mail to a single recipient with the given subject
* @param mailMsg The message needed to be send as plain text
* @param recipientAddresses The mail addresses in an array to which the mail has to be sent
* @param subject The subject of the mail to be sent
* @throws MailSenderException this exception wraps the MailException throw by the Spring framework
*/
public void sendMessage(String mailMsg,String recipientAddress,String subject)throws MailSenderException;

/**
* This method sends the mail to multiple recipients which are given as comma separated values, with the given subject
* @param mailMsg The message needed to be send as plain text
* @param recipientAddresses The mail addresses in an array to which the mail has to be sent
* @param subject The subject of the mail to be sent
* @throws MailSenderException this exception wraps the MailException throw by the Spring framework
*/
public void sendMessageWithCommaSeparatedMailAddresses(String mailMsg,String recipientAddress,String subject)throws MailSenderException;
}

This is the main contract which any calling party can use to send mails. The method is overloaded so that clients can call with different functionality. Next I show you the implmentation of this interface as well as the exception class that i have defined which wraps the MailException thrown by Spring. I wrapped it so that any calling party only needs to know about the MailSending module and not about Spring exceptions.


package com.test.commons.mailservices.core.remoting.ejb.bl;

import org.apache.log4j.Logger;
import org.springframework.mail.MailException;
import org.springframework.mail.MailSender;

import com.test.commons.mailservices.core.exceptions.MailSenderException;
import com.test.commons.mailservices.core.remoting.ejb.service.MailSenderService;

/**
* This is the Main class involved in sending email message to the outside world<br>
* The class uses the Spring Framework which wraps the java mail API to send mails.
* Common functionality of obtaining a SimpleMailMessage object is given by the parent<br>
* class named MailSenderCommon. The instance variables of the class are instantiated with<br>
* through a spring config. The spring config file responsible is mailconfig.spring.xml found <br>
* under the resources directory.
*
* @author dinuka
*
*/
public class MailSenderImpl extends MailSenderCommon implements MailSenderService {

private static final Logger log = Logger.getLogger(MailSenderImpl.class);

private MailSender mailSender;

private String fromAddress;

public MailSenderImpl() {

}

/**
* {@inheritDoc}
*/
public void sendMessage(String mailMsg, String[] recipientAddresses, String subject)throws MailSenderException {
if (mailMsg == null || recipientAddresses == null) {
log.error("Input parameters received for sendMessage(String,String[]) are null");
}

sendEmail(mailMsg, subject, recipientAddresses);

}

/**
* {@inheritDoc}
*/
public void sendMessage(String mailMsg, String recipientAddress, String subject)throws MailSenderException {
if (mailMsg == null || recipientAddress == null) {
log.error("Input parameters received for sendMessage(String,String) are null");
throw new IllegalArgumentException("Received Input Parameters Are Null");
}
sendEmail(mailMsg.trim(), subject, recipientAddress);
}

/**
* {@inheritDoc}
*/
public void sendMessageWithCommaSeparatedMailAddresses(String mailMsg, String recipientAddress, String subject)throws MailSenderException {

if (mailMsg == null || recipientAddress == null) {
log
.error("Input parameters received for sendMessageWithCommaSeparatedMailAddresses(String,String) are null");
throw new IllegalArgumentException("Received Input Parameters Are Null");
}
sendEmail(mailMsg, subject, recipientAddress.split(","));

}

public MailSender getMailSender() {
return mailSender;
}

public void setMailSender(MailSender mailSender) {
this.mailSender = mailSender;
}

public String getFromAddress() {
return fromAddress;
}

public void setFromAddress(String fromAddress) {
this.fromAddress = fromAddress;
}

private void sendEmail(String mailMsg, String subject, String... address)throws MailSenderException {

try {
mailSender.send(getSimpleMessage(mailMsg, fromAddress, subject, address));
} catch (MailException ex) {
log.error("MailSenderImpl: sendMessage() Exception occured" + ex.getMessage());
throw new MailSenderException(ex.getMessage());
}
}

}





package com.test.commons.mailservices.core.remoting.ejb.bl;

import java.util.Date;

import org.springframework.mail.SimpleMailMessage;

public class MailSenderCommon {

/**
* This is the common method which creates a simple message object which is used to send mails out
* Note that var arg is used as the second parameter to facilitate String[] and normal String object parsing
* to the same method. Also please note that you should always keep the var arg parameter as the last parameter in
* this method as the specification requires it.
* @param mailMsg
* @param addresses
* @return
*/
protected SimpleMailMessage getSimpleMessage(final String mailMsg, final String fromAddress,String subject,final String... addresses) {
SimpleMailMessage message = new SimpleMailMessage();
message.setSentDate(new Date());
message.setTo(addresses);
message.setFrom(fromAddress);
message.setSubject(subject);
message.setText(mailMsg);


return message;
}

}




package com.test.commons.mailservices.core.exceptions;

public class MailSenderException extends Exception{

/**
*
*/
private static final long serialVersionUID = -6281925344129197510L;

private String message;





public MailSenderException(String message){
this.message = message;
}

@Override
public String getMessage() {
return message;
}
}



Then we have the SMTP Authenticator class which is used for mail authentication. It is as follows;


package com.jkcs.commons.mailservices.core.remoting.ejb.bl;

import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;

public class SmtpAuthenticator extends Authenticator {
private String username;
private String password;

public SmtpAuthenticator(String username, String password) {
super();
this.username = username;
this.password = password;
}

public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}

}


And finally you the following spring xml shows how to configure and integrate all this together.



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

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


<!-- our Authenticator implementation -->
<bean id="smtpAuthenticator"
class="com.test.commons.mailservices.core.remoting.ejb.bl.SmtpAuthenticator">
<constructor-arg>
<value>${outgoing.mail.server.userid}</value>
</constructor-arg>
<constructor-arg>
<value>${outgoing.mail.server.password}</value>
</constructor-arg>

</bean>

<!-- now setup an authenticated session -->
<bean id="mailSession" class="javax.mail.Session"
factory-method="getInstance">
<constructor-arg>
<props>
<prop key="mail.smtp.auth">true</prop>
<!-- <prop key="mail.smtp.socketFactory.port">465</prop>
<prop key="mail.smtp.socketFactory.class">
javax.net.ssl.SSLSocketFactory
</prop>
<prop key="mail.smtp.socketFactory.fallback">
false
</prop> -->
</props>
</constructor-arg>
<constructor-arg ref="smtpAuthenticator" />
</bean>


<bean id="mailService" class="com.test.commons.mailservices.core.remoting.ejb.bl.MailSenderImpl">
<property name="mailSender" ref="mailSender"/>
<property name="fromAddress">
<value>${outgoing.mail.server.userid}</value>
</property>
</bean>

<!-- Mail service -->
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host">
<value>${outgoing.mail.server.ip}</value>
</property>
<property name="port">
<value>${outgoing.mail.server.port}</value>
</property>
<property name="username">
<value>${outgoing.mail.server.userid}</value>
</property>
<property name="password">
<value>${outgoing.mail.server.password}</value>
</property>
<property name="session" ref="mailSession" />
<property name="javaMailProperties">
<props>
<!-- Use SMTP-AUTH to authenticate to SMTP server -->
<prop key="mail.smtp.auth">true</prop>
<prop key="mail.smtp.sendpartial">true</prop>
<!-- Use TLS to encrypt communication with SMTP server -->
<!-- <prop key="mail.smtp.starttls.enable">true</prop>
<prop key="mail.smtp.sendpartial">true</prop> -->

</props>
</property>
</bean>

</beans>


As you can see i have used parameters as ${var_name}. This is because i have used Spring property file loading mechanism. Hence those variables are taken from a .property file. To configure that use the following;


<bean id="PropertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<!--
The order of these properties files is important, as properties
will override one another
-->
<value>xxx.properties</value>
<value>mail.properties</value>
</list>
</property>
</bean>


Thats about it. Hope this would be helpful to someone who is looking to do the same.