Archive for May, 2012

Calcutta

Posted: May 23, 2012 in Uncategorized

Calcutta.

Inheritance vs Aggregation

Posted: May 22, 2012 in Techilla

Inheritance vs Aggregation/ Composition vs Inheritance/ Is-a or Has-a ? Call it by any name, but this quandary is something which has baffled many design studies.
The other day I was designing some POC with Hibernate, and I got bitten by the performance bug. Having prior experience with Hibernate, I know what a beast it can be in terms of performance especially with complex inheritance mappings or associations .

As is often the case with me, one thing led to another and I veered down the Google way 🙂 . To paraphrase many eminent people, who have pretty much pushed me towards aggregation,let me provide a gist below:

An inheritance can always be rewritten as an association as follows

instead of


public class A {}
public class B extends A {}

we can use

public class B {
private A a;
}

We should use aggregation if part of the interface(available methods for us to override) is not used or has to be changed to avoid an illogical situation.

We only need to use inheritance, if we need almost all of the functionality without major changes. And when in doubt,we should always use Aggregation.
Also another line of thought was :
1.Whatever design strategy you choose, your choice will likely be the wrong one at some point because of changing requirements
2.Changing that choice is difficult once you’ve made it.
3.Inheritance tends to be a worse choice as it’s more constraining and hence we should go for aggregation.

To quote a discussion between Bill Venners and Erich Gamma  at:

Bill Venners: That extra flexibility of composition over inheritance is what I’ve observed, and it’s something I’ve always had difficulty explaining. That’s what I was hoping you could capture in words. Why? What is really going on? Where does the increased flexibility really come from?

Erich Gamma: We call this black box reuse. You have a container, and you plug in some smaller objects. These smaller objects configure the container and customize the behavior of the container. This is possible since the container delegates some behavior to the smaller thing. In the end you get customization by configuration. This provides you with both flexibility and reuse opportunities for the smaller things. That’s powerful. Rather than giving you a lengthy explanation, let me just point you to the Strategypattern. It is my prototypical example for the flexibility of composition over inheritance. The increased flexibility comes from the fact that you can plug-in different strategy objects and, moreovers, that you can even change the strategy objects dynamically at run-time.

Bill Venners: So if I were to use inheritance…

Erich Gamma: You can’t do this mix and match of strategy objects. In particular you cannot do it dynamically at run-time.

So, the writing’s on the wall for me. Choose aggregation over inheritance whenever you can, and hopefully, you will live to design another project before they find out that the design strategy implemented needs to be changed. 🙂

All info above are drawn from inheritance-vs-aggregation
and “Design principle” so all credit goes to original authors and I just summarized it above.

Logging a Spring +Hibernate application is especially useful during the initial stages when you would want to see whether all Hibernate configurations are fine. It might also be useful at the later stages to look at the query log generated to do some optimization. However, logging of combined Spring and Hibernate related data onto the same log file is not very straightforward (until you read this post, that is :). Its primarily because Spring and Hibernate use different logging technologies

Spring uses Jakarta Commons Logging API (JCL) which is mandatory to be in the classpath or the application context doesn’t get loaded.

Hibernate 3.3+ uses SL4J or Simple Logging Façade for Java

I have always used log4j to have a common logging repository for our application,

Now, for all these to work together and post everything onto the log file, we need the following libraries in our classpath:

  • commons-logging-1.1.1.jar
  • log4j-1.2.13.jar
  • slf4j-api-1.6.1.jar
  • slf4j-log4j12-1.6.4.jar

The last jar is the bridge between SL4J and log4j, however note that sl4j-log4j* and sl4j-jdk* cannot remain on the classpath at the same time, or they cause binding issues, so look out for that.(Will print on the logs if you have any such binding issues)

Finally, our log4j.xml which will contain the logging info.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
	debug="false">

	<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="[%d{dd/MM/yy hh:mm:ss:sss z}] %5p %c{2}: %m%n" />
		</layout>
	</appender>

	<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
		<appender-ref ref="CONSOLE" />
		<appender-ref ref="FILE" />
	</appender>

	<appender name="FILE" class="org.apache.log4j.RollingFileAppender">

		<param name="File" value="C:/log/spring-hib.log" />
		<param name="MaxBackupIndex" value="100" />

		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="[%d{dd/MM/yy hh:mm:ss:sss z}] %5p %c{2}: %m%n" />
		</layout>

	</appender>

	<category name="org.hibernate">
		<priority value="DEBUG" />
	</category>

	<category name="java.sql">
		<priority value="debug" />
	</category>

	<root>
		<priority value="INFO" />
		<appender-ref ref="FILE" />
	</root>

</log4j:configuration>

Note : org.hibernate will show the full blown list of boiler plate stuff , so it might be worthwhile to trim down to org.hibernate.SQL.

Also, if u put hibernate.show_sql=true in your configuration file, it will print the sql statement in the console as well.

There is a very nice pictorial representation here which shows the various binding among different loggers and it pointed me in the right direction, thanks Espen!:)

Uploading a file or an image and retrieving it is an extremely frequent activity and doing so via Mybatis/Spring must be a breeze as there are so many users who must be doing it!

So I thought, 6 hours before I started to code it. Unfortunately , Mybatis user manual has zero references to blob/clob insert /delete and searching on Google didn’t seem to go very far. There were pointers but no complete code examples. In the end, it proved to be exceedingly simple and I went to sleep a happy man. Here’s the full example to save half a day for somebody else.

Mybatis version : mybatis-3.1.0
Spring version : 3.1.1
Mybatis-Spring bundle : 1.1.1
Database : Oracle 10.2.0.4
Reqd. libs : commons-fileupload-*.jar , commons-io*.jar , ojdbc14.jar and obviously the reqd. spring and mybatis jars.

Database columns in EMPLOYEE table:

FILENAME VARCHAR2 (100 Byte),
FILECONTENTTYPE VARCHAR2 (100 Byte),
FILEDATA BLOB.

The actual file data is stored in a BLOB field.

Note: not a CLOB field, as we are mainly trying to host images here.(Even if some other file type is uploaded, it being stored as a BLOB will help to retrieve it exactly as it was stored, without any character encoding being applied, as in case of CLOB)

We are having a Spring MVC application, so we will augment our web-config.xml or whatever config file the DispatcherServlet listens to with the below code:


<bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<property name="maxUploadSize">
		<value>10000000</value>
	</property>
</bean>

The fileupload size is in Bytes.

Model object / Form data

@Alias(value="emp")
public class Employee {
       private CommonsMultipartFile fileData;
       private byte[] fileDataBytes;
       private String fileName;
       private String fileContentType;
       //getters/setters
}

Our jsp will host the below :

spring form file upload

If we don’t put the enctype=”multipart/form-data, we will not be able to typecast the uploaded file into the CommonsMultiPartFile and hence we will not be able to retrieve the contentType and the filename. If we don’t put the encType, we can always retrieve the uploaded file as byte[] but in order to retrieve the file, we will have to store the contenttype as well, so an easier option is to use CommonsMultiPartFile.

Store or Upload the file or image in Mybatis


<update id="updateEmployee" parameterType="com.spring.model.Employee">
	update employee
	<set>
<if test="fileData.originalFilename != null">filename = #{fileData.originalFilename,jdbcType=VARCHAR},</if>
		<if test="fileData.ContentType != null">fileContentType =					#{fileData.contentType,jdbcType=VARCHAR},</if>
		<if test="fileData.bytes != null">fileData = 							#{fileData.bytes},
</if>
	</set>
	where
	empId = #{empId}
</update>

Note, that we don’t set the jdbcType of contentType, nor do we use any typehandlers as many suggested.

Also, note that we use the original CommonsMultipart object to retrieve the fileContentType,filename and fileData.

That’s it for storing the file.

Retrieve the uploaded file/image using Mybatis

Now, for retrieving it back, we will use the below query:

<select id="getUploadedFileForEmployee" parameterType="Long"
		resultType="emp">
		select empId,fileName,fileContentType,fileData as
		fileDataBytes
		from
		employee where
		empId=#{empId}

</select>

That’s it. We have successfully retrieved the file along with its name and contenttype. Now, we shall see how we can display it / download the file.

@Controller
public class EmployeeController {
	@Autowired
	private EmployeeBaseService employeeService;
	@Autowired
	private UploadedObjectView uploadedObjectView;
	public EmployeeBaseService getEmployeeService() {
		return employeeService;
	}
     //getters,setters
         @RequestMapping(value="/employeeDownloadFile")
	public ModelAndView downloadFile(@RequestParam("empId") long empId){
		Map model = new HashMap();
		Employee empMap = employeeService.getUploadedFileForEmployee(empId);
		model.put("data", empMap.getFileDataBytes());
		model.put("contentType", empMap.getFileContentType());
		model.put("filename", empMap.getFileName());
		return new ModelAndView(uploadedObjectView, model);
	}

For the save of the employee along with its data and a detailed explanation of the annotations, please refer here.

Ok, so we are done with our controller, but since the file to be downloaded can be of different types, so we construct a generic UploadedObjectView and populate it with the file data.

public class UploadedObjectView extends AbstractView {
	//To rediect to another page, with inline text.
	protected void renderMergedOutputModel1(Map model,
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		  byte[] bytes = (byte[]) model.get("data");
	      String contentType = (String) model.get("contentType");
	      response.setContentType(contentType);
	      response.setContentLength(bytes.length);
	      ServletOutputStream out = response.getOutputStream();
	      out.write(bytes);
	      out.flush();
	}
	//For a download option
	@Override
	protected void renderMergedOutputModel(Map model,
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		byte[] bytes = (byte[]) model.get("data");
		String contentType = (String) model.get("contentType");
		response.addHeader("Content-disposition","attachment; filename="+model.get("filename"));
		response.setContentType(contentType);
		response.setContentLength(bytes.length);
		ServletOutputStream out = response.getOutputStream();
		out.write(bytes);
		out.flush();
	}
}

We have 2 methods above:

If we override with the 1st method, the output will be redirected to another page with an inline text / image.

For a totally generic implementation, the overridden method 2 is safer as it provides with a download option.

That’s it folks :)! I hope this could be a help to somebody.

One common error which I have encountered in Mybatis while uploading large files was :

SQL state [72000]; error code [1013]; ORA-03111: break received on communication channel

This error is due to the query timeout being exceeded.

From the mybatis-config.xml(more info here), changed the value from 10 to 100 to resolve this issue.

<setting name="defaultStatementTimeout" value="100" />

Great post here by Juergen Hoeller if you need further inputs or just anything about Spring in particular. Thanks Juergen!

Goal of this session

  • Mybatis Mapper xmls and interfaces creation
  • Mybatis MapperFactoryBean to retrieve Mybatis SqlSessions which are threadsafe.
  • Mybatis MapperScannerConfigurer to automatically wire the mapper interfaces
  • Mybatis SqlSessionDaoSupport and SqlSessionTemplate
  • Spring Annotated Controllers
  • Spring example of get, post methods to retrieve and update an object.

Ok, so we have done our configurational changes here.

We have created our datasource, sqlsessionfactorybean, mybatis configurational file and referred to our mybatis mapper xmls.But we haven’t yet created the model object or the mapper xmls.

Step 1:  Model Object Creation : We will create the Employee object first.

public class Employee {
	protected long empId;
	protected String firstname;
	protected String lastname;
	protected String email;
	protected String telephone;
	protected String birthday;

          // we will see these properties later
	private CommonsMultipartFile fileData;
	private byte[] fileDataBytes;
	private String fileName;
	private String fileContentType;
          //getters and setters for all attributes.
	}

Step 2: Creating the Mybatis interfaces and mapper xmls.

Lets start with the interfaces. We had 2 interfaces BaseMapperInterface and EmployeeMapperInterface. Of these, BaseMapperInterface is a marker interface.

We will go straight to the EmployeeMapperInterface. There are multiple ways to do it, so I will show the legacy way first.

package com.mybatis.dao;
public interface EmployeeMapperInterface extends BaseMapperInterface{
public List getEmployeeWithId(Long id);
public int insertEmployee(Employee e);
public int updateEmployee(Employee e);
public void deleteEmployee(Long id);
//other data access methods.
}

Now, we will define the EmployeeMapper.xml

<?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.mybatis.dao.EmployeeMapperInterface">
<select id="getEmployeeWithId" parameterType="Long" resultType="emp">
		select empId,firstname,lastname,emailId as email,birthday,fileName from
		employee where
		1=1
		<if test="_parameter != null">
			AND empId=#{empId}
		</if>
		order by empId
	</select>
<insert id="insertEmployee" parameterType="com.spring.model.Employee">
		<!--
			the interface returns int, not long otherwise typecast errors were
			thrown
		-->
		<selectKey keyProperty="empId" resultType="Long" order="BEFORE">
			select Hibernate_Sequence.nextval as empId from dual
  		</selectKey>

		insert into employee(empId,firstname,lastname,emailId,filename,fileContentType,fileData )
		values(#{empId},#{firstname},#{lastname},#{email},#{fileData.originalFilename,jdbcType=VARCHAR},
			#{fileData.contentType,jdbcType=VARCHAR},#{fileData.bytes} )

	</insert>

   <update id="updateEmployee" parameterType="com.spring.model.Employee">
		update employee
		<set>
			<if test="firstname != null">firstname= #{firstname,jdbcType=VARCHAR},</if>
			<if test="lastname != null">lastname =#{lastname,jdbcType=VARCHAR},</if>
			<if test="email != null">emailid = #{email,jdbcType=VARCHAR},</if>
			<if test="fileData.originalFilename != null">filename = #{fileData.originalFilename,jdbcType=VARCHAR},</if>
			<if test="fileData.ContentType != null">fileContentType =	#{fileData.contentType,jdbcType=VARCHAR},</if>
			<if test="fileData.bytes != null">fileData = #{fileData.bytes},</if>
		</set>
		where
		empId = #{empId}
	</update>

	<delete id="deleteEmployee" parameterType="Long">
		delete from employee
		where empId = #{empId}
	</delete>

Now, if you see the above xml, you would see a select, insert , update and delete tags. Don’t worry, we would go through each of them later in this tutorial. For now, we shall see the implementation of this interface.

Step 3 : Legacy way of defining the implementation of the interface.
Remember MapperFactoryBean on the 1st post? Its not required if we follow this legacy approach and the changed mapper-config.xml will look like below

<bean id="employeeMapper" class ="com.mybatis.dao.EmployeeMapperImpl">
   <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

Obviously we should still follow the inheritance strategy as defined earlier and this referring of sqlSessionFactory directly by employeeMapper is just for demonstration purposes.

I say this legacy because with MapperFactoryBean this is no longer required. We can work only with the interfaces. However, life is not always so beautiful and we have to look at old code in order to debug , maintain or improve.


public class EmployeeMapperImpl extends SqlSessionDaoSupport implements EmployeeMapperInterface{

	@Override
	public void deleteEmployee(Long id) {
		getSqlSession().delete("com.mybatis.dao.EmployeeMapperInterface.deleteEmployee", id);
	}

	@Override
	public List<Employee> getEmployeeWithId(Long id) {
		return getSqlSession().selectList("com.mybatis.dao.EmployeeMapperInterface.getEmployeeWithId", id);

	}

	@Override
	public int insertEmployee(Employee e) {
		return getSqlSession().insert("com.mybatis.dao.EmployeeMapperInterface.insertEmployee", e);	}

	@Override
	public int updateEmployee(Employee e) {
		SqlSessionTemplate tm= (SqlSessionTemplate) getSqlSession();
		int id = tm.update("com.mybatis.dao.EmployeeMapperInterface.updateEmployee", e);
		//getSqlSession().rollback();
		return id;
	}
}

Now, before we start explaining, we would slightly veer off from the MVC pattern and we shall look at how a standalone Mybatis application would work . For a detailed explanation, please visit here.

At the core of all Mybatis stuff, is an SqlSessionFactory which opens and closes SqlSession. SqlSession is not thread safe and needs to be aligned with the HttpRequest cycle in case of a web application.

 For Spring Mybatis, there are 3 ways to retrieve the sessions :

i. extend SqlSessionDaoSupport as we are doing above and retrieve the session using getSqlSession(). This method returns a thread-safe SqlSession which we can use in our Spring transactions. Then, this session can be used to perform insert/update/delete/selectOne/selectList operations.

ii. We can also use SqlSessionTemplate. We can instantiate it in the database-config.xml

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
 <constructor-arg index="0" ref="sqlSessionFactory" />
</bean>

As can be seen above, it can also be instantiated by using the sqlSessionFactory.

SqlSession sqlSsession = new SqlSessionTemplate(sqlSessionFactory);

To summarize, SqlSessionTemplate should always be used instead of SqlSession because the base MyBatis SqlSession cannot participate in Spring transactions and is not thread safe. Switching between the two classes in the same application can cause data integrity issues.
Also, in step i. when we do getSqlSession, we actually retrieve SqlSessionTemplate, so the below statement would work fine.

SqlSessionTemplate tm= (SqlSessionTemplate) getSqlSession();

iii.  Finally the MapperFactoryBean
Instead of using SqlSessionDaoSupport or SqlSessionTemplate directly from the DAOs, we can use MapperFactoryBean to inject interface DAOs into our service classes.


<bean id="baseMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
	<property name="mapperInterface" 									value="com.mybatis.dao.BaseMapperInterface" />
	<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

<bean id="employeeMapper" parent="baseMapper">
<property name="mapperInterface" value="com.mybatis.dao.EmployeeMapperInterface" />
</bean>

The MapperFactoryBean handles creating an SqlSession as well as closing it. If there is a Spring transaction in progress, the session will also be committed or rolled back when the transaction completes. Finally, any exceptions will be translated into Spring DataAccessExceptions.

MapperScannerConfigurer and automatically marking the interfaces

Finally, those of you who don’t want to spend lots of time in wiring down each and every interface bean, can use the MapperScannerConfigurer which allows you to automatically scan the directories and mark the mapper interfaces.
1. Define the MapperScannerConfigurer and mark the basePackage.


<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
     <property name="basePackage" value="org.mybatis.spring.sample.mapper" />
</bean>

2. The mapper interfaces which are referred in the service classes need to be autowired, since their references will no longer be present in the mapper-config.xml

3. Finally, sqlSessionFactory also needs to be configured(contrary to the Mybatis manual), else the mappers will not work and will throw this exception :

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ’employeeMapperInterface’ defined in file [C:\anirban\Work_Ani\SpringIntegration\WebRoot\WEB-INF\classes\com\mybatis\dao\EmployeeMapperInterface.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property ‘sqlSessionFactory’ or ‘sqlSessionTemplate’ are required

Note: There was an issue with PropertyPlaceHolderConfigurer not working when used in conjunction with mybatis-spring-3.1.0. Its resolved by replacing with mybatis-spring-3.1.1 bundle.

Thats it folks for the Mybatis stuff for this session. Now, lets jump to the Spring related changes . Recall that ,                                                                                             

 Request –> Spring MVC controller –> accesses Service facade –> accesses the DAO xml/interface.

We are done with the last leg(DAO xml/interface) and we will now construct the Service facade.
As always to encourage good coding practices, we will create an interface for the EmployeeService.

public interface EmployeeBaseService {
	public Employee getEmployeeById(long empId);
	public long saveEmployee(Employee employee) throws Exception;
	public void deleteEmployee(long empId);

}

Now, the actual implementation of the service:

@Service
public class EmployeeService implements EmployeeBaseService{

	@Autowired
	EmployeeMapperInterface employeeMapper;
         //getters, setters
         @Override
	public Employee getEmployeeById(long empId){
		//retrieve from database
		List empList = employeeMapper.getEmployeeWithId(empId);
		if(empList != null && empList.size()>0){
			return (Employee) empList.get(0);
		}
		return null;

	}

	@Override
	public long saveEmployee(Employee employee){
		long empId = 0l;
		if(employee.getEmpId()==0){
			empId  = new Long( employeeMapper.insertEmployee(employee));
		}else{
			 employeeMapper.updateEmployee(employee);
			 empId  =  employee.getEmpId();
		}
		return empId;
	}

	@Override
	public void deleteEmployee(long empId) {
		employeeMapper.deleteEmployee(empId);

	}

Annotated Employee Controller

@Controller
public class EmployeeController {
	@Autowired
	private EmployeeBaseService employeeService;

          @RequestMapping(value = "/employeeHome",method=RequestMethod.GET)
	public String displayHomePage(@RequestParam("empId") long empId,ModelMap m){
		System.out.println("employeeHome>> "+empId);
		//retrieve the employee with this id.
		Employee employee = null;
		Employee empMap = employeeService.getEmployeeByIdMap(empId);
		if(empId ==0){
			employee = new Employee();
		}else{
			employee = employeeService.getEmployeeById(empId);

		}
		m.addAttribute("employee",employee);
		System.out.println(employee);
		return ProjectConstants.SECURE_FOLDER+"employeeHome";
	}
         @RequestMapping(value="/employeeEdit",method=RequestMethod.POST)
	public String saveEmployee(@ModelAttribute("employee")
                Employee emp,  BindingResult br) throws Exception{
		if(br.hasErrors()){
			return "employeeHome";
		}
		System.out.println(emp);

		employeeService.saveEmployee(emp);
		return "redirect:employeeHome.html?empId="+emp.getEmpId();
	}

Ok, lets go over it. The controller contains a reference to the EmployeeBaseService and this is autowired.
First the displayHomePage() which is accessed via a GET.

 

Points to note :

1. @RequestParam(“”) is used to bind a request parameter to a method parameter.  If a RequestParam is specified, it becomes mandatory for the URI to contain it.Else, can  be used as @RequestParam(value=””,required=false)

2.  This method has a signature :                                                                                              String * (@RequestParam(“<param>”) datatype method-arg,ModelMap model)

3.  ModelMap.addAttribute(“paramName”,<param>). This paramName is important. As it has to be set in the view as the modelattribute, else the jsp will not be rendered and the following exception will come:
Neither BindingResult nor plain target object for bean name ‘command’ available as request attribute
4.  Returns the viewname , so essentially there would be a employeeHome.jsp lying around under ProjectConstants.SECURE_FOLDER.

5. @RequestMapping(value = “/employeeHome”,method=RequestMethod.GET) means this method would be invoked when we have a call like :
http://localhost:8080/springProj/employeeHome.html?empId=92178033
Note : the request parameter being passed.

Next, the saveEmployee() which is accessed via the POST.

  1. Annotation @ModelAttribute as the method parameter. This is used to retrieve the command object, after filling out the form.
  2. Returns a redirect to the url which is going to be picked up the get method, the redirect prevents an accidental re-update upon refreshing the screen.
  3.  @RequestMapping(value=”/employeeEdit”,method=RequestMethod.POST) will invoke this method, meaning there must be a form whose action would point to employeeEdit.html

Finally, lets complete this tutorial by showing the view (*. jsp) which will render the model.

Spring ModelAttribute JSP

Features to be noted in this jsp:

  1. modelAttribute “emp” is necessary as mentioned earlier.
  2. <form:form method=”post” action=”employeeEdit.html”  , so basically this will look like an employee personal details update form where the employee is redirected to his/her view page after the update.

 

Right that’s it.

We are going to use Spring 3x and Mybatis 3x in conjunction here.

Pre-requisite :
Download the Mybatis-Spring bundle : mybatis-spring-1.1.1-bundle and use the libs assorted.
Spring version : 3.1.1
Mybatis version : 3.1.0
Please note the version 1.1.1 for mybatis-spring bundle. There were some issues with 1.1.0 bundle for loading of properties using Spring’s PropertyPlaceHolderConfigurer, but more on that later.

Mybatis

Mybatis is a persistence framework. Mybatis is not an ORM framework and doesn’t map Java objects to database rows. However, it maps methods to SQL statements.

Mybatis vs. Hibernate

I have used both Mybatis and Hibernate in my applications, and both have their pros and cons. However, of late, I have moved more and more towards Mybatis.

IMO, if the object graph is complex, then it is better to use Mybatis and not Hibernate. Hibernate has its own version of lazy loading, but the more associations an object has or the heavier an object is, the more it becomes a performance hit.

In one of our applications which used Hibernate, we finally had to rewrite several queries in order to perform thin loading, or loading only those attributes which are required.

For further details regarding Mybatis, please visit http://en.wikipedia.org/wiki/MyBatis
For Spring-Mybatis, :here

Spring vs Struts for MVC

As regards Spring vs Struts for MVC, again to each his own. Struts 2x is pretty good when it comes to writing less code to do more and I had recently developed an application using Struts 2x. However, most of the transaction management there was programmatic, which needless to say is ugly and error prone. I had to spend lots of time testing out my code.

Now, this last statement is not strictly a Spring MVC advantage or a Struts flaw, because its just an MVC framework and nothing more. However, when we talk about Spring, we get to use the IOC container as well along with its declarative transaction management. Plus, the community support is really good, which invariably helps if you hit a roadblock. One more thing, which I really like about Spring is its view-agnostic (Yes I picked up this word somewhere on the net) It means that it really allows you to custom build any view implementation you like and not just stick to JSPs.(Though Struts 2x has some similar implementations using FreeMarker)

We would be using Eclipse as an IDE to do our development and this is an image of all jars which will be required eventually. Some of them like the commons*.jar and mybatis-ehcache*.jar will have to be downloaded separately.

spring mybatis libs/ jars

Since, by now we have a working Spring MVC application here, we will piggyback on it and add the required configurations. We will revisit our application’s web.xml. (This is just the relevant part, for the entire xml, please refer here.)

<context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>
 /WEB-INF/spring/app-config.xml
 /WEB-INF/spring/database-config.xml
 /WEB-INF/spring/mapper-config.xml
 </param-value>
 </context-param>
<listener>
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>

Right, so from here we can see that the ContextLoaderListener will check on

  1. database-config.xml which will contain the database configuration.
  2. mapper-config.xml which will point to the individual Mybatis interfaces.
database-config.xml
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
 destroy-method="close">
 <property name="driverClassName" value="${driver}" />
 <property name="url" value="${url}" />
 <property name="username" value="${username}" />
 <property name="password" value="${password}" />
 <property name="defaultAutoCommit" value="false" />
 </bean>
<bean id="txManager"
 class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
 <property name="dataSource" ref="dataSource" />
 </bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
 <property name="dataSource" ref="dataSource" />
 <property name="mapperLocations" value="classpath:com/mybatis/mappers/*.xml" />
 <property name="configLocation" value="WEB-INF/mybatis-config/mybatis-config.xml" />
 </bean>

We see 3 beans here :dataSource, txManager and sqlSessionFactory . For dataSource, we will be using dbcp’s BasicDataSource. We would come to the txmanager later.

Now, if you are observant, you would see that the credentials of the datasource are encoded. This is an industry standard, where sensitive information is stored on a keystore or an external property file. Then, the access for this file is controlled by the system administrators on the server. We would see later how, Spring help to retrieve these property values.

For now, let’s concentrate only on the sqlSessionFactory and its attributes.

It has 3 attributes :

  1. refers to the dataSource,
  2. mapperLocations which is where we would store our mybatis xml files. Ant style configuration for mapperLocation: if we put it as value=“classpath*:com/mybatis/mappers/*.xml” /> then it will also look into the subpackages recursively
  3. configLocation where we would store a custom mybatis configuration file to override some important settings.

mapper-config.xml

<bean id="baseMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
 <property name="mapperInterface" value="com.mybatis.dao.BaseMapperInterface" />
 <property name="sqlSessionFactory" ref="sqlSessionFactory" />
 </bean>
<bean id="employeeMapper" parent="baseMapper">
 <property name="mapperInterface" value="com.mybatis.dao.EmployeeMapperInterface" />
 </bean>

2 important concepts explained here:

  1. We have a BaseMapperInterface which contains a reference to the sqlSessionFactory and this class is simply extended by the rest of the mapper interfaces so that individual interfaces do not have to link in the sqlSessionFactory.
  2. Presence of a MapperFactoryBean which we will revisit later.

mybatis-config.xml

This is a bare-bones configuration file which we will augment as we learn more about Mybatis.

<?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>
 <settings>
 <setting name="cacheEnabled" value="true" />
 <setting name="lazyLoadingEnabled" value="true" />
 <setting name="multipleResultSetsEnabled" value="true" />
 <setting name="useColumnLabel" value="true" />
 <setting name="useGeneratedKeys" value="false" />
 <setting name="defaultExecutorType" value="SIMPLE" />
 <setting name="defaultStatementTimeout" value="100" />
 <setting name="safeRowBoundsEnabled" value="false" />
 <setting name="mapUnderscoreToCamelCase" value="false" />
 <setting name="localCacheScope" value="SESSION" />
 <setting name="jdbcTypeForNull" value="OTHER" />
 <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString" />
 </settings>
</configuration>

So, we have done our configurations. One more small thing of using Spring to decipher the properties for us. We can put this in the app-config.xml which is also listened to by the ContextLoaderListener(check the web.xml earlier on this page)

<bean class=<em>"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"</em>>
<property name="location">
<value>classpath:config.properties</value>
</property>
</bean>

Interesting Note: we can use our custom PropertyPlaceHolderConfigurer by extending the above mentioned class.We only need to override the following method :

public String convertPropertyValue(final String originalValue) {
//whatever decoding/decrypting logic u want to put.
//U can first encrypt and then encode the property in the property file.
}

Right, so our configurational changes have been completed.

Now a typical approach is having the service layer get access to the Mapper interfaces.

So, the interaction would be like Controller(Web layer) accesses the Service Façade which accesses the Mybatis DAO layer/interfaces.

Our sample application would have a login screen for a manager. When the manager successfully logs in, he or she would be able to view his/her employees. On clicking any of the employee’s hyperlink, the manager would get access to the employee’s details which can then be modified.

In step 2, we will be creating our controllers.

This tutorial has been linked in Mybatis wiki : http://code.google.com/p/mybatis/wiki/FeedbackArticles?ts=1337254913&updated=FeedbackArticles

We spent 3 nights and 4 days in Ubud, Bali in Indonesia for our honeymoon and here’s me trying to etch them on electronically. 🙂

Hotel stay: While Google searched for our accommodation and what to do for ‘3 days in Ubud’ , somebody on one of the search pages came up with a gem , suggesting that exotic beaches or mountains are best kept for later vacations as you would mostly be exploring your partner during the honeymoon, and hence spending most of the time in the hotels 🙂

Even though we courted for about 8 years, this thought stuck and Tripadvisor came up with Viceroy Bali as the most romantic hotel/resort in Ubud.

We chose the honeymoon package in a Terrace Villa including a full 5 course romantic dinner at Cascades and a 2 hour couples spa at Lembah, their in-house restaurants and spa centres respectively. The resort and our villa was very pretty with all the ingredients to make the stay worthwhile including a private dip pool overlooking the Ayung river gorge. The service was excellent, and the views exotic from the room.

viceroy bali terrace villa

Day 0 : We board a Silk Air flight from Kolkata to Singapore where we reach early morning and halt for about 2 hours. We then proceed to Denpasar on a Singapore Airlines flight. The flight is exceedingly cold and we shiver inspite of a couple of blankets.

Day 1: We reach Denpasar in the afternoon, and are greeted by a hotel employee,Nyoman as was agreed.

Immigration is a breeze, when assisted by Nyoman. Ubud is about an hours drive and we sit back and relax.  The hotel is exceedingly beautiful and the views from our rooms stunning.

Our hotel is about 3 km from the town centre and the hotel car takes us there in about 10 min. We visit Murni’s Warung. I had read so much about it, it almost appears like a historical visit. Murni’s is the oldest restaurant in Ubud and we are seated in the second storey. I try out the satee and the smoked duck.

 

Duck sauce is really yummy. The duck itself appeared to have been overdone. I wanted to have the babi guling, but my wife forbids me, so I stick to the chicken.

smoked duck @ Murni

Tip : Go during the day to catch the views around the warung. 

 Day 2 : Wake up and rush for breakfast at Cascades. The ala carte breakfast consists of monstrous servings of eggs . I go for a salmon-2 eggs – caviare combo while my wife settles for the less adventurous traditional omelette with 3 eggs. We book a car from the hotel and go for a trip to the Pura Kehen temple, in Bangli regency (Ubud is in Gianyar) about 1 hour  from the hotel. Our driver, Margi also serves as the guide and explains the various stories.

Bali is mostly Hindu and many stone sculptures point to Ramayana and Mahabharata, the two Hindu epics. Pura Kehen is very beautiful and mostly devoid of tourists. We were the only ones in the entire compound.

While coming back, we visited Tirta Empul / Tampak Siring, the famous hot water spring temple. Legend has it that Indra, the Hindu God created this hot water spring to bring his soldiers back to life. Mayadanawa, the evil king had prohibited all religious offerings and proclaimed himself as God. To restore parity, there ensued a war during which the evil king poisoned the waters of the holy army which drank it and died.

Till this day, many Balinese men and women bathe there to sanctify themselves and pray. The main hot water spring is however closed to public. Beautiful but a tourist hotspot, so a bit on the crowded side.

We finish dinner with a full 5 course meal at Cascades. Good food , though could have been better. The prices are exorbitant, but I believe the views from the restaurant should definitely make up for some of it.Since, this was included in our original package and since it was dinner time, it was a split choice for us. The desert however almost makes up for any blemishes.

Day 3: We wake up early morning , have breakfast and rush to raft at the Ayung river. Sobek is the organizing party and provides for an excellent guide and buffet lunch at the end of the trip .The rafting is awesome, pretty sedate, but fun nevertheless. Have to climb down about 200 steep steps to get to the river and climb up some fewer. Thankfully, the lunch happens in between, so makes the up trot easy. Definitely need to carry extra pair of clothing and slippers during rafting.

 Our guide is really funny and we enjoy the whole show. Our boat is brought under a waterfall for a few moments and the water falls with a deafening force. Very beautiful sceneries all along the 11 km stretch along with lots of stone carvings on the way.

After we come back , we have spa at the Lembah. The spa is quite good, and the flower bath is the creme de la creme.

In the evening, the hotel car again drops us to the town center and we meander along the Monkey Forest Road, looking for some souvenirs.A Buddha bust catches our eyes and we buy three bronze pieces at 70 USD after some haggling.

Have dinner at a non-descript restaurant on the Monkey Forest Road. The food turns out to be quite good. My wife,however doesn’t like it much , and sticks to some vegetarian side dish.

Day 4 : Have another flower bath in the morning, this time in the villa, after breakfast. We then go to the airport and lol around for an hour before boarding another super cold Singapore Airlines flight to Singapore.

In Singapore. we have a transit gap of about 5 hours. We visit the butterfly garden in Terminal 3. Very pretty indeed with loads of butterflies

butterfly garden Singapore airport

Girls love to shop and my wife indulges in some at the Singapore airport. Finally, we board another Singapore Airlines flight to Kolkata, with tired limbs but memories of a lifetime!!