Feeds:
Posts
Comments

Archive for the ‘JAVA’ Category

Recently I stumbled upon a particular Spring project  called Spring Loaded .The ReadMe section did catch my attention because it boosts developer productivity by reloading class files as and when they change.

There have been quite a few projects which provide such benefits and I believe the most popular commercial choice is JRebel. Those guys have done a great job in turning  one of the greatest JAVA Web developers pain into a line of business.  However there have been alternatives but none so simple as JRebel

Fortunately Spring Loaded was quite simple to use and configure. Its just a single jar. However, I am quite sure it is not a sophisticated as  other commercial options. But its getting there and is currently being used in Grails 2.

ReLoading in Action

The most reliable  way to show automatic reloading in action is by capturing a video. Unfortunately you guys will just have to trust me.

Start off by downloading the jar and including in your normal java project.

Create a POJO “Person”


public class Person {
	
	
	
	public  void printBody()
	{

		System.out.println("*********");
		this.hands();
//		this.gloves();
		System.out.println("Body");
		this.legs();
//		this.shoes();
		System.out.println("*********");
	}
	
	private  void hands()
	{
		System.out.println("Hands");
	}
	
	private  void gloves()
	{
		System.out.println("Gloves");
	}		
	
	private  void legs()
	{
		System.out.println("Legs");
	}	
	
	private  void shoes()
	{
		System.out.println("Shoes");
	}	

}

Now create a class to run the POJO

public class LiveEcho {

	
	public static void main(String[] args) throws Exception {
		
		while(true)
		{
			Thread.sleep(5000);
			new Person().printBody();

		}
		
	}
}

When you run the LiveEcho class you will see statements in the console like below.

*********
Hands
Body
Legs
*********
*********
Hands
Body
Legs
*********
*********
Hands
Body
Legs
*********

Nothing amazing. While the application is running, try uncommenting out “this.gloves()” or “this.shoes()”. Still nothing amazing.

In order to let Spring Loaded to be aware of the changes, we need to pass “-javaagent:springloaded-1.1.5.RELEASE.jar” as a java argument. I have done it here from my eclipse option

SprngLoadedConfig

SprngLoadedConfig

Run the LiveEcho class again. This time while the class is running, try uncommenting out “this.gloves()” or “this.shoes()”. You will see the output on the console changing

*********
Hands
Body
Legs
*********
*********
Hands
Body
Legs
*********
*********
Hands
Body
Legs
*********
*********
Hands
Gloves
Body
Legs
*********
*********
Hands
Gloves
Body
Legs
*********
*********
Hands
Gloves
Body
Legs
Shoes
*********
*********
Hands
Gloves
Body
Legs
Shoes
*********

As you can see, Spring Loaded has noticed the changes in the Person class files and reloaded the changes without re-starting the JVM.

Further reading

There are different ways of checking whether the classes have re-loaded or what are the changes that have taken place.

Q. How do I know when a reload has occurred so I can clear my state? A. You can write a plugin that is called when reloads occur and you can then take the appropriate action. Create an implementation of ReloadEventProcessorPlugin and then register it via SpringLoadedPreProcessor.registerGlobalPlugin(plugin). (There are other ways to register plugins, which will hopefully get some documentation!)

I have not tried it out on complex web project and their likes, but I am sure they are getting there.

Read Full Post »

 
Recently I was in need to tune some of the java services which I had implemented for for an iPhone project. When integrating services with mobile and hand held devices, it is very important that the services respond in a matter of seconds. In order to tune the services and get the best UI experience, the obvious step is to find the slowest service. However the intriguing question was ….HOW?

Following are some of the alternates most developers do

  • Have a System.out / Log.debug after you enter and before you exit the service, which prints the time
  • Write and aspect using AOP and log the time before and after invocation of the method

 

Serious developers choose the second approach, since monitoring is a cross cutting concern.

Before you fire up you IDE and start writing an Aspect and all those AOP jargon, I would like to introduce you to a class from the Spring Framework core portfolio called “JamonPerformanceMonitorInterceptor”. As the name suggests, it is an AOP interceptor that hooks into the framework called JAMon. JAMon is a java monitoring framework and it sure is sweet.

To know more about JAMon check it out HERE. Make sure you download the jamon-2.7.jar file and put it on your classpath

That’s right, no writing of interceptors and joint points and what not AOP jargon out there.

All you need to to do is instantiate a JamonPerformanceMonitorInterceptor bean and tell it which all Spring beans to intercept

Add this to instantiate the bean

<bean id="jamonPerformanceMonitorInterceptor" class="org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor" >
   <property name="trackAllInvocations" value="true"></property>
   <property name="useDynamicLogger" value="true"></property>
</bean>

Next create a “BeanNameAutoProxyCreator” and hook in the interceptor.

<bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
	<property name="interceptorNames">
		<list>
			<idref bean="jamonPerformanceMonitorInterceptor"/>
		</list>
	</property>
	<property name="beanNames">
		<list>
			<value>aRegularSpringBean</value>
			<value>statisticsDao</value>
			<value>statisticsService</value>
			<value>paymentDao</value>	
			<value>paymentService</value>				
		</list>
	</property>
</bean>

All you need to do now is, tell the BeanNameAutoProxyCreator which all Spring beans to intercept.”paymentDao”,”paymentService” etc are all classic Spring beans. Voila, your services and dao are all being monitored.

Oh…And one last thing.

Make sure you set the log4 logging level to TRACE or else it will NOT work!!

In the follow article , I shall show you have to generate reports from the JAMON framework using a simple servlet.

Read Full Post »

Some time back, I was in need to invoke a simple WebService and that’s when one of my colleagues brought to my notice the simplicity of WSIF. Initially it looked to me as though it’s very simple. However I had to struggle a bit to invoke a simple WebService. I believe the reason for that was their poor documentation.

Needless to say WSIF was the brain child of IBM folks (do correct me if I am wrong) and has been prominently used in this space.

This article is just to show how to invoke a simple WebService which takes a FLAT XML request object and returns a FLAT XML response.

Below is the WSDL of the WebService in question. All it does is spit back a concatenated string of what you spit at it.

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:ns1="http://org.apache.axis2/xsd" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:ns="http://ws.apache.org/axis2" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" targetNamespace="http://ws.apache.org/axis2">
    <wsdl:types>
        <xs:schema attributeFormDefault="qualified" elementFormDefault="unqualified" targetNamespace="http://ws.apache.org/axis2">
            <xs:element name="showEcho">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element minOccurs="0" name="value" nillable="true" type="xs:string"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
            <xs:element name="showEchoResponse">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element minOccurs="0" name="return" nillable="true" type="xs:string"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
        </xs:schema>
    </wsdl:types>
    <wsdl:message name="showEchoRequest">
        <wsdl:part name="parameters" element="ns:showEcho"/>
    </wsdl:message>
    <wsdl:message name="showEchoResponse">
        <wsdl:part name="parameters" element="ns:showEchoResponse"/>
    </wsdl:message>
    <wsdl:portType name="TestPortType">
        <wsdl:operation name="showEcho">
            <wsdl:input message="ns:showEchoRequest" wsaw:Action="urn:showEcho"/>
            <wsdl:output message="ns:showEchoResponse" wsaw:Action="urn:showEchoResponse"/>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="TestSoap11Binding" type="ns:TestPortType">
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
        <wsdl:operation name="showEcho">
            <soap:operation soapAction="urn:showEcho" style="document"/>
            <wsdl:input>
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output>
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:binding name="TestSoap12Binding" type="ns:TestPortType">
        <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
        <wsdl:operation name="showEcho">
            <soap12:operation soapAction="urn:showEcho" style="document"/>
            <wsdl:input>
                <soap12:body use="literal"/>
            </wsdl:input>
            <wsdl:output>
                <soap12:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:binding name="TestHttpBinding" type="ns:TestPortType">
        <http:binding verb="POST"/>
        <wsdl:operation name="showEcho">
            <http:operation location="Test/showEcho"/>
            <wsdl:input>
                <mime:content type="text/xml" part="showEcho"/>
            </wsdl:input>
            <wsdl:output>
                <mime:content type="text/xml" part="showEcho"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="Test">
        <wsdl:port name="TestHttpSoap11Endpoint" binding="ns:TestSoap11Binding">
            <soap:address location="http://10.142.20.66:8080/axis2/services/Test.TestHttpSoap11Endpoint/"/>
        </wsdl:port>
        <wsdl:port name="TestHttpSoap12Endpoint" binding="ns:TestSoap12Binding">
            <soap12:address location="http://10.142.20.66:8080/axis2/services/Test.TestHttpSoap12Endpoint/"/>
        </wsdl:port>
        <wsdl:port name="TestHttpEndpoint" binding="ns:TestHttpBinding">
            <http:address location="http://10.142.20.66:8080/axis2/services/Test.TestHttpEndpoint/"/>
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>

NOTE: This WebService was developed with the help of AXIS 2 runtime. I just created a normal java class and put the complied class file (after renaming its extension from .class to .aar) into the repository folder of the AXIS 2 server.

Now the Class used to invoke the WebService


package com.datel.transliterator.app;

import org.apache.log4j.Logger;
import org.apache.wsif.WSIFException;
import org.apache.wsif.WSIFMessage;
import org.apache.wsif.WSIFOperation;
import org.apache.wsif.WSIFPort;
import org.apache.wsif.WSIFService;
import org.apache.wsif.WSIFServiceFactory;
import org.apache.wsif.providers.soap.apacheaxis.WSIFDynamicProvider_ApacheAxis;
import org.apache.wsif.util.WSIFPluggableProviders;

public class WSInvoke {
	
	Logger log = Logger.getLogger(RunNow.class);
	
	public static void main(String[] args) throws Exception 
	{
		new WSInvoke().invoke();		
	}
		
    public void invoke() throws Exception
    {
		String result = null;
		
        WSIFPluggableProviders.overrideDefaultProvider("http://schemas.xmlsoap.org/wsdl/soap/",
        		new WSIFDynamicProvider_ApacheAxis()
    
        );
       
        // create a service factory
        WSIFServiceFactory factory = WSIFServiceFactory.newInstance();
        WSIFService service = factory.getService(
	                "http://localhost:8080/axis2/services/Test?wsdl", //Location of the WSDL
	                null,
	                null,
	                "http://ws.apache.org/axis2", //TargetNamespace as per the WSDL
	                "TestPortType"); //PortType as per the WSDL

	        WSIFPort port = service.getPort();
	 

	        // create the operation
	        WSIFOperation operation = port.createOperation("showEcho");
	        
      

	        // create the input, output and fault messages associated with this operation
	        WSIFMessage input = operation.createInputMessage();
	        WSIFMessage output = operation.createOutputMessage();
	        WSIFMessage fault = operation.createFaultMessage();
	        
      
	        /*VALUE : BECAUSE OF THE attribute VALUE
	          <xs:element name="showEcho">
				<xs:complexType>
					<xs:sequence>
						<xs:element minOccurs="0" name="value" nillable="true" type="xs:string"/>
					</xs:sequence>
				</xs:complexType>
			   </xs:element>

        	  <xs:element name="showEchoResponse">
				<xs:complexType>
					<xs:sequence>
						<xs:element minOccurs="0" name="return" nillable="true" type="xs:string"/>
					</xs:sequence>
				</xs:complexType>
				</xs:element>
        	  */	        
	        input.setObjectPart("value", " Hi there");
       
	        if (operation.executeRequestResponseOperation(input, output, fault)) 
	        {

	        	result = (String) output.getObjectPart("return");
	            System.out.println(result);
	             
	        } 
	        else 
	        {
	        	System.out.println("Invocation failed");
	            // extract fault message info
	        }
             
    }

}


We have created an “input” request object and set it with a key value pair, where the key is “name”. This is because the XML request object takes an attribute “name”

We have created an “output” response object and get it with a key value pair, where the key is “return”. This is because the XML response object takes an attribute “return”

Important:
This example is assuming the structure of the XML request and response object. I have only been able to using this type of invocation for FLAT XML objects. For complex XML request object please wait for PART 2 to see how its invoked.

Read Full Post »

Oracle JDeveloper SUCKS!!!

I really couldn’t help but write this after I found out how to create a folder with JDeveloper.

Do you agree or disagree?

Read Full Post »

I was trying to access a secure web site using Apache HttpClient API. However, it was failing giving me the following exception

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

In apache HttpClient website, it states that “HttpClient provides full support for HTTP over Secure Sockets Layer (SSL) or IETF Transport Layer Security (TLS) protocols by leveraging the Java Secure Socket Extension (JSSE).

I tried their example of accessing a secure website and it worked. However the website I was trying to access is still failing.

After debugging the problem I came across a good article. In the article, the author mentioned that the above exception comes in the following case “when trying to open an SSL connection to a host using JSSE. What this usually means is that the server is using a test certificate (possibly generated using keytool) rather than a certificate from a well known commercial Certification Authority such as Verisign or GoDaddy. Web browsers display warning dialogs in this case, but since JSSE cannot assume an interactive user is present it just throws an exception by default.

That was not exactly my case. I was not getting a warning from the web browser. The web site I was trying to access was using a commercial certificate but it was not a very well known. It was from a regional authority and not an international authority. Any key store comes with a default set of certificates from well known authorities.

So, I ran the program mentioned in the article. A file called jssecacerts was generated which includes the certificate. I have placed the file in the JAVA_HOME\jre\lib\security directory. Finally I was able to access the secure web site successfully.

Read Full Post »

This article is a small POC on how the readOnly attribute used in Spring Transaction strategy improves database access in case of transactions that involve only READing data from datasources.

First a small extract from the Spring reference documentation:

The TransactionDefinition interface specifies:
• Isolation: the degree of isolation this transaction has from the work of other transactions. For example, can this transaction see uncommitted writes from other transactions?
• Propagation: normally all code executed within a transaction scope will run in that transaction. However, there are several options specifying behavior if a transactional method is executed when a transaction context already exists: for example, simply continue running in the existing transaction (the common case); or suspending the existing transaction and creating a new transaction. Spring offers all of the transaction propagation options familiar from EJB CMT.
• Timeout: how long this transaction may run before timing out (and automatically being rolled back by the underlying transaction infrastructure).
• Read-only status: a read-only transaction does not modify any data. Read-only transactions can be a useful optimization in some cases (such as when using Hibernate).

As you can see the Read-only status seems to be silver bullet for transactions that involve only reading data. Following is a setup that I used to prove the point.

The setup included a Service method which in turn calls the DAO layer to access a table and ONLY retrieve records. The time required to access the data is calculated both WITH and WITHOUT the readOnly attribute. The time is calculated using Spring’s StopWatch utility class. However you can use your own timing methodologies to check out the outcome. The application is run for sometime to warm up the JVM followed by the actual estimation of the time. This is clear in the Main.java class

This test is run on the following configuration machine:

JDK: 1.5
MySQL: 5.0.26
Records in DB: 1,000,000 plus records
RAM: 1.5 GB
Processor: Pentium 1.8GHz

DAO Class : DAOStep.java


package com.tx.app.dao;

import java.sql.Types;
import java.util.Calendar;
import java.util.List;

import org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class DAOStep extends  NamedParameterJdbcDaoSupport implements IDAOStep
{
	


	public void getData(int x) 
	{

		final String insertIntoTest = "insert into TEST(VAL1,VAL2) values(?,?) ";

		List val=getJdbcTemplate().queryForList("select 1 from test where val1= ? order by 1 desc" , new Object[]{x},new int[]{Types.INTEGER});
		
	}
	

}

This DAO class only queries a table name “TEST” with the following query

SELECT 1 from TEST where val1=? ORDER BY 1 DESC

Next is the Service Class : ServiceStep.java


package com.tx.app.service;

import com.tx.app.dao.IDAOStep;
import com.tx.app.exception.MyCheckedException;
import com.tx.app.exception.MyRuntimeException;

public class ServiceStep 
{

	private IDAOStep daoStep;
	
	
	
	public void getReadOnlyData(int x) 
	{
		daoStep.getData(x);

		
	}	
	
	public void getNoReadOnlyData(int x) 
	{
		daoStep.getData(x);
		
	}	

	public IDAOStep getDaoStep() {
		return daoStep;
	}

	public void setDaoStep(IDAOStep daoStep) {
		this.daoStep = daoStep;
	}
	
	
}

Next is the Main Class : Main.java


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

import com.tx.app.dao.IDAOStep;
import com.tx.app.exception.MyCheckedException;
import com.tx.app.service.ServiceStep;


public class Main 

{

	
	
	public static void main(String[] args) throws MyCheckedException 
	{
	
		ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"context.xml"});
		ServiceStep service = (ServiceStep)context.getBean("serviceStepTX");
		
		
/*Warm Up for the application and the JVM*/
		for (int i = 0; < 10; i++)
		{
			service.getNoReadOnlyData(1);
			service.getReadOnlyData(1);
		}

		
		

		long readOnlyTime =0;
		long noReadOnlyTime =0;
		int runTime =500;
		
		for (int i = 0; i < runTime; i++) 
		{

		
		
		StopWatch watch = new StopWatch("Read-Only-Data");
		//watch.start("First Task");
		service.getReadOnlyData(1);
		//watch.stop();
		watch.start("Second Task");
		service.getReadOnlyData(2);
		watch.stop();
		watch.start("Third Task");		
		service.getReadOnlyData(3);
		watch.stop();
		watch.start("Four Task");		
		service.getReadOnlyData(4);
		watch.stop();
		watch.start("Five Task");		
		service.getReadOnlyData(5);
		watch.stop();		
		watch.start("Six Task");		
		service.getReadOnlyData(6);
		watch.stop();		
		//System.out.println(watch.prettyPrint());
		//System.out.println(watch.shortSummary());
		readOnlyTime = readOnlyTime+watch.getTotalTimeMillis();
		}
		

		for (int i = 0; i < runTime; i++) 
		{
			
		
		StopWatch watch1 = new StopWatch("No-Read-Only-Data");
		//watch.start("First Task");
		service.getNoReadOnlyData(1);
		//watch.stop();
		watch1.start("Second Task");
		service.getNoReadOnlyData(2);
		watch1.stop();
		watch1.start("Third Task");		
		service.getNoReadOnlyData(3);
		watch1.stop();
		watch1.start("Four Task");		
		service.getNoReadOnlyData(4);
		watch1.stop();
		watch1.start("Five Task");		
		service.getNoReadOnlyData(5);
		watch1.stop();		
		watch1.start("Six Task");		
		service.getNoReadOnlyData(6);
		watch1.stop();		
		//System.out.println(watch1.prettyPrint());
		//System.out.println(watch1.shortSummary());
		noReadOnlyTime = noReadOnlyTime+watch1.getTotalTimeMillis();
		
		
		}
		
		System.out.println("Read Only : "+(readOnlyTime/runTime));
		System.out.println("No Read Only : "+(noReadOnlyTime/runTime));
		
	}
	
	
}
&#91;/sourcecode&#93;


<strong>Finally the Spring XML configuration file</strong>




<?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-2.5.xsd">
	

   
    <bean id="faceDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
   		<property name="driverClass" value="com.mysql.jdbc.Driver"/>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/facedb"/>
		<property name="user" value="root"/>	
		<property name="password" value=""/>	
		<property name="initialPoolSize"><value>3</value></property>		
		<property name="minPoolSize"><value>5</value></property>	
		<property name="acquireIncrement"><value>5</value></property>		
        <property name="acquireRetryAttempts"><value>10</value></property>
        <property name="acquireRetryDelay"><value>1000</value></property>
        <property name="checkoutTimeout"><value>600000</value></property>
        <property name="maxPoolSize"><value>25</value></property>
        <property name="maxStatements"><value>200</value></property>
        <property name="maxStatementsPerConnection"><value>20</value></property>
        <property name="maxIdleTimeExcessConnections"><value>600</value></property>
    </bean>
    
	
	<bean id="daoStep" class="com.tx.app.dao.DAOStep">
		<property name="dataSource" ref="faceDataSource"/>
	</bean>
	
	<bean id="serviceStep" class="com.tx.app.service.ServiceStep">
		<property name="daoStep"  ref="daoStep"/>
	</bean>
	
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    	<property name="dataSource" ref="faceDataSource"/>
    </bean>
    

	<bean id="serviceStepTX" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager" ref="txManager"/>
		<property name="target" ref="serviceStep"/>
		<property name="proxyTargetClass" value="true"/>		
		<property name="transactionAttributes">
			<props>
				<prop key="getReadOnly*">PROPAGATION_REQUIRED,readOnly</prop>	
				<prop key="getNoReadOnly*">PROPAGATION_REQUIRED</prop>				
			</props>
		</property>
	</bean>    
	
    
</beans>

Once Now create a table in the MySQL database with the following script

CREATE TABLE TEST
(VAL1 INT,
VAL2 INT) engine=innodb;

CREATE INDEX TEST_INDEX on TEST(VAL1);

OUTPUT
———-

Once you run the Main.java class you will see an output similar to this.

Read Only : 15
No Read Only : 30

The interpretation of this output is that a SELECT on the table

With readOnly attribute took an average of 15 ms
Without readOnly attribute took an average of 30 ms

Pretty good I suppose!!!

Read Full Post »

I have been using Spring TX Management for quite sometime until I recently came upon an article describing the common pitfalls that occur in Transaction Strategies. Although many cases were covered, I would like to describe the common one that is seen in most code.

I am going to explain it with the help of a sample example. In the example we shall put together a sample Service which in turn calls a DAO. The service will call two methods from the DAO. It is only a trivial Service-DAO example.

First the DAO class : DAOStep.java


package com.tx.app.dao;

import java.sql.Types;
import java.util.Calendar;

import org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class DAOStep extends  NamedParameterJdbcDaoSupport implements IDAOStep
{
	

	public void updateData(int val1 , int val2) 
	{
	
		final String insertIntoTest = "UPDATE TEST SET VAL1= ? where VAL2= ? ";

		getJdbcTemplate().update(insertIntoTest,
				new Object[]{
							val1,
							val2
							},
				new int[]{
						 Types.INTEGER,
						 Types.INTEGER,
					});

	}
	

	public void insertData(int val1 , int val2) 
	{
		
		
		final String insertIntoTest = "insert into TEST(VAL1,VAL2) values(?,?) ";

		getJdbcTemplate().update(insertIntoTest,
				new Object[]{
							val1,
							val2
							},
				new int[]{
						 Types.INTEGER,
						 Types.INTEGER,
					});

	}
	

}

Next the Service class : ServiceStep.java

package com.tx.app.service;

import com.tx.app.dao.IDAOStep;
import com.tx.app.exception.MyCheckedException;
import com.tx.app.exception.MyRuntimeException;

public class ServiceStep 
{

	private IDAOStep daoStep;
	
	public void doStepRuntimeException()
	{
		daoStep.insertData(2, 2);
		daoStep.updateData(-2, 2);
		throw new MyRuntimeException();

		
	}
	
	public void doStepCheckedException() throws MyCheckedException
	{
		daoStep.insertData(2, 2);
		daoStep.updateData(-2, 2);
		throw new MyCheckedException();

		
	}	

	public IDAOStep getDaoStep() {
		return daoStep;
	}

	public void setDaoStep(IDAOStep daoStep) {
		this.daoStep = daoStep;
	}

	


	
	
}

As you can see the service throws two exceptions, one a checked exception(MyCheckedException) and second a runtime exception (MyRuntimeException).

Next the Runtime Exception class : MyRuntimeException.java

package com.tx.app.exception;

public class MyRuntimeException extends RuntimeException
{

}

Next the Checked Exception class: MyCheckedException.java

package com.tx.app.exception;

public class MyCheckedException extends Exception
{

}

And the main class to bootstrap the application

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

import com.tx.app.dao.IDAOStep;
import com.tx.app.exception.MyCheckedException;
import com.tx.app.service.ServiceStep;


public class Main 

{

	
	
	public static void main(String[] args) throws MyCheckedException 
	{
	
		ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"context.xml"});
		ServiceStep service = (ServiceStep)context.getBean("serviceStepTX");
		/*Method One*/
		service.doStepRuntimeException();
		/*Method Two*/
		service.doStepCheckedException();
		
		
		
	}
	
	
}

Finally the Spring XML context file : 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: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">
	

   
    <bean id="faceDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
   		<property name="driverClass" value="com.mysql.jdbc.Driver"/>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/facedb"/>
		<property name="user" value="root"/>	
		<property name="password" value=""/>	
		<property name="initialPoolSize"><value>3</value></property>		
		<property name="minPoolSize"><value>5</value></property>	
		<property name="acquireIncrement"><value>5</value></property>		
        <property name="acquireRetryAttempts"><value>10</value></property>
        <property name="acquireRetryDelay"><value>1000</value></property>
        <property name="checkoutTimeout"><value>600000</value></property>
        <property name="maxPoolSize"><value>25</value></property>
        <property name="maxStatements"><value>200</value></property>
        <property name="maxStatementsPerConnection"><value>20</value></property>
        <property name="maxIdleTimeExcessConnections"><value>600</value></property>
    </bean>
    
	
	<bean id="daoStep" class="com.tx.app.dao.DAOStep">
		<property name="dataSource" ref="faceDataSource"/>
	</bean>
	
	<bean id="serviceStep" class="com.tx.app.service.ServiceStep">
		<property name="daoStep"  ref="daoStep"/>
	</bean>
	
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    	<property name="dataSource" ref="faceDataSource"/>
    </bean>
    

	<bean id="serviceStepTX" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager" ref="txManager"/>
		<property name="target" ref="serviceStep"/>
		<property name="proxyTargetClass" value="true"/>		
		<property name="transactionAttributes">
			<props>
				<prop key="doStepRuntimeException*">PROPAGATION_REQUIRED</prop>
				<prop key="doStepCheckedException*">PROPAGATION_REQUIRED</prop>				
			</props>
		</property>
	</bean>    
	
    
</beans>

The Table that needs to be there in some database is TEST. I am using MySQL database and following is the script used to create the TEST table

CREATE TABLE TEST
(VAL1 INT,
VAL2 INT) engine=innodb

Question

As you can see the Transaction attribute for the doStepRuntimeException and doStepCheckedException are both PROPAGATION_REQUIRED. What do you think would be the outcome when the Main class is executed once with Method 1 and once with Method 2? Would the records be inserted as well as updated in the database?

Explanation

The answer is follows.

Method 1)
The whole transaction is rolled back as RuntimeException is thrown and the current transaction is Rolled back

Method 2)
The whole transaction is committed as a checked exception (Exception) is thrown and the current transaction is Commited.

The correct way to rollback both the transactions would be to alter the XML file as follows

<bean id="serviceStepTX" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager" ref="txManager"/>
		<property name="target" ref="serviceStep"/>
		<property name="proxyTargetClass" value="true"/>		
		<property name="transactionAttributes">
			<props>
				<prop key="doStepRuntimeException*">PROPAGATION_REQUIRED,-MyRuntimeException</prop>
				<prop key="doStepCheckedException*">PROPAGATION_REQUIRED,-MyCheckedException</prop>				
			</props>
		</property>
	</bean>  

However, if you want to rollback all checked exceptions you can use -Exception instead of -MyCheckedException. The default behaviour is for Unchecked exception the current transaction is rolled back and for Checked exception the current transaction is commited.

Read Full Post »

Older Posts »