Showing posts with label spring. Show all posts
Showing posts with label spring. Show all posts

Saturday, October 14, 2017

Deploy Java Web Application on Heroku with Heroku CLI

This post will describe how to create and deploy a Java Web Application war to Heroku using Heroku CLI. You will need a basic understanding of Git and Maven, and have Git and Maven already installed on your system.
Pre-requisites
  • Install Java 8, Maven and Git. For this post, I used Java 8 and Maven 3.5.
  • Create a free account on heroku.com. This account will be used from Heroku CLI to login
  • Download and Install Heroku CLI from here.
Following are the high-level steps to follow
  1. Create a Simple Spring Web Application.
  2. Create an application on Heroku
  3. Create the Procfile
  4. Create app.json
  5. Update Maven pom.xml
  6. Push code to Heroku

Monday, September 18, 2017

Auto-Restart Spring Boot Application On Code Change With Dev Tools

Spring Boot Dev Tools enables auto-restarting a Spring boot application whenever any class is changed in the class path. This is not comparable in speed with the hot swap functionality offered by Jrebel or Spring Loaded, but this is a very simple and easy way to implement and better than manual restart. In this post, I use a simple Spring boot rest echo service to demonstrate how spring boot dev tools can be used to auto restart the application when using Maven on an IDE or Gradle from command line. In either options, the main trigger for a restart is the change to a class file, which means that the change to a Java file has to be compiled either by the IDE in option 1 or by Gradle in option 2.

Sunday, September 10, 2017

Load Environment Specific Properties Files Using Spring

One of the more common aspects of enterprise application development involves environment specific properties files. Some examples include Database configurations or external JMS resources etc. The common way to address this problem is to use multiple properties file an build the Application EAR/WAR/JAR at compile time. Although this works, this solution also means that we maintain different build scripts for different environments, or having some file renames etc. while building the application. Spring profiles address this problem in a more efficient way. Like any other property, using Spring profiles, we can inject the environment profile into Spring and Spring will handle the loading of the appropriate configuration files. In this post, I show how to load environment specific properties files using Spring.

Monday, July 10, 2017

Mybatis Spring Integration

This post will give a quick introduction into integrating MyBatis and Spring with a very basic application. I will describe only the integration using XML based configuration. As always with MyBatis, this starts with setting up SqlSessionFactory from Spring. Instead of configuring the datasource and mapping in mybatis-config.xml, all configuration will be setup in Spring configuration. The only additional configuration will be the Mapper.xml file.

Sunday, July 09, 2017

Spring Standalone Application Setup with Gradle

This post is a continuation of the Spring Standalone Application post. In this post I will go over the application setup and the Gradle build file used for building the project. The assumption here is that Gradle is already installed on the machine and ready to use. For instructions on how to install Gradle please go the Gradle installation page.

Continue to full post ...

Application Setup

Following is the directory structure I had for this project. In case of the Annotation based approach, you don't need the resources folder.

+---SpringStandalone
    |   build.gradle
    |               
    \---src
        +---main
        |   \---java
        |       +---main
        |       |       SpringStandaloneTest.java
        |       |       
        |       \---service
        |               TestService.java
        |   \---resources
        |           applicationContext.xml
        |               
        \---test
            \---java

Gradle Build File: Gradle Application Plugin

The Gradle Application plugin is very useful for creating Standalone applications that can be run using gradle run. By default, the Gradle Application plugin applies the java plugin and Distribution plugin. You can configure the main class and any JVM arguments that you may want to pass to the application. To pass the main class name, you can use the mainClassName parameter like below

mainClassName = "main.SpringStandaloneTest"
And to pass any JVM arguments to the application, you can use applicationDefaultJvmArgs as shown below
applicationDefaultJvmArgs = ["-Dprop=val"]
And here is the full build.gradle file I used for the spring standalone application
apply plugin:'application'
mainClassName = "main.SpringStandaloneTest"
applicationName = 'SpringStandalone'

repositories {
    jcenter()
}

dependencies {
  compile group: 'org.springframework', name: 'spring-core', version: '4.3.9.RELEASE'
 compile group: 'org.springframework', name: 'spring-context', version: '4.3.9.RELEASE'
 compile group: 'org.springframework', name: 'spring-beans', version: '4.3.9.RELEASE'
 compile group: 'org.springframework', name: 'spring-tx', version: '4.3.9.RELEASE'
 compile group: 'org.springframework', name: 'spring-orm', version: '4.3.9.RELEASE'

    // Use JUnit test framework
    compile 'junit:junit:4.12'
}


applicationDefaultJvmArgs = ["-Dprop=val"]

Standalone Spring Application

Having a basic spring standalone application ready always helps when you want to do a quick POC or test of new libraries or tools you plan to use. This post shows a couple of ways in which you can setup a basic Spring standalone application.

  • Spring Standalone application with ApplicationContext XML Configuration file.
  • Spring Standalone application with Annotations

Continue to full post...

For this application I will use a simple service class TestService that has a single method echo(), which returns the Upper case version of any string passed as a parameter. The TestService class will be used a component to be injected into the main application class.

Spring Standalone application with ApplicationContext XML Configuration file

In this model we have 4 files

  1. SpringStandaloneTest.java
  2. TestService.java
  3. applicationContext.xml
  4. build.gradle (will go over the gradle build in the next post)
Following are the files used for this application

SpringStandaloneTest.java
package main;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import service.TestService;

public class SpringStandaloneTest {

 public static void main(String[] args) {
  ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  SpringStandaloneTest test = ctx.getBean("springStandalone", SpringStandaloneTest.class);
  test.callService();

 }

 private TestService testService = null;

 private void callService() {
  System.out.println(testService.echo("Hello"));

 }

 public TestService getTestService() {
  return testService;
 }

 public void setTestService(TestService testService) {
  this.testService = testService;
 }

}
TestService.java
package service;

public class TestService {
 
 public String echo(String str) {
  return str.toUpperCase();
 }

}
applicationContext.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"
 xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

 <bean name="testService" class="service.TestService" />
 <bean name="springStandalone" class="main.SpringStandaloneTest">
  <property name="testService" ref="testService"></property>
 </bean>

</beans>

Spring Standalone application with Annotations

In this model, we will setup the standalone application with annotations instead of the applicationContext.xml file. The annotation @Component is used to define a class as a Spring component, so that Spring can detect it as a Spring bean. The @ComponentScan is used to direct Spring where to look for Components. It is similar to the directive when using Spring XML configuration. The following is the code used to implement the Standalone Spring application using annotations.

SpringStandaloneTest.java
package main;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import service.TestService;

@ComponentScan(basePackages= {"main", "service"})
public class SpringStandaloneTest {

 public static void main(String[] args) {
  ApplicationContext context = new AnnotationConfigApplicationContext(SpringStandaloneTest.class);

  SpringStandaloneTest test = context.getBean(SpringStandaloneTest.class);
  test.callService();
  
 }

 @Autowired
 private TestService service = null;

 private void callService() {
  System.out.println(service .echo("Hello"));

  
 }

}
TestService.java
package service;

import org.springframework.stereotype.Component;

@Component
public class TestService {
 
 public String echo(String str) {
  return str.toUpperCase();
 }

}
In the next post I will describe the Gradle build setup used for this standalone application.

Tuesday, July 03, 2012

Integrate Jersey and Spring

This post describes a way to integrate spring with Jersey resource classes. It expands on the earlier sample Restful Web Services With Jersey API. The code here has been implemented on following configuration
  • Tomcat 7
  • Java 7
  • Spring 3.1.1
  • Jersey 1.12
To show the use of Spring, I added MyService class which will be injected into RestWS class. For this example, we start out with the sample code in Restful Web Services With Jersey API and make the following changes...
  1. Web.xml: In the Web Deployment Descriptor, the Jersey Servlet has to be modified to use com.sun.jersey.spi.spring.container.servlet.SpringServlet instead of com.sun.jersey.spi.container.servlet.ServletContainer
    <?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_3_0.xsd"
        id="WebApp_ID" version="3.0">
        <display-name>JerseyRest</display-name>
        <welcome-file-list>
            <welcome-file>index.html</welcome-file>
        </welcome-file-list>
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/applicationContext.xml</param-value>
        </context-param>
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    
        <servlet>
            <servlet-name>Jersey Web Application</servlet-name>
            <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
            <init-param>
                <param-name>com.sun.jersey.config.property.packages</param-name>
                <param-value>com.blogspot.aoj.restws</param-value>
            </init-param>
    
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>Jersey Web Application</servlet-name>
            <url-pattern>/rest/*</url-pattern>
        </servlet-mapping>
    </web-app>
  2. RestWS: There is not much change in the RestWS.java file, other than adding the field MyService which will be injected by spring. The following sample code shows @Autowire, which works with @Component annotation for spring to inject dependencies. However, you can implement the same example without Autowiring by simply creating a bean in spring context file.
    /**
     * @author Abhi Vuyyuru
     */
    
    package com.blogspot.aoj.restws;
    
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.PathParam;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import com.blogspot.aoj.service.MyService;
    
    @Path("/restws")
    @Component
    public class RestWS {
        
        @Autowired
        private MyService myService;
    
        @GET
        @Path("concat/i/{i}/j/{j}")
        @Produces(MediaType.TEXT_HTML)
        public String concat(@PathParam("i") String i, @PathParam("j") String j) {
            return myService.concat(i, j);
        }
    
        public MyService getMyService() {
            return myService;
        }
    
        public void setMyService(MyService myService) {
            this.myService = myService;
        }
    
    }
  3. /WEB-INF/applicationContext.xml: The following code shows code for Autowire and otherwise. Simply comment the unused version
    <?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:p="http://www.springframework.org/schema/p"     xmlns:context="http://www.springframework.org/schema/context"     xsi:schemaLocation="             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">         <bean id="myService" class="com.blogspot.aoj.service.MyService" />     <bean id="restWS" class="com.blogspot.aoj.restws.RestWS">         <property name="myService" ref="myService"></property>     </bean>     <!-- <context:component-scan base-package="com.blogspot.aoj.restws" /> --> </beans>
  4. Client will be the same as used in the previous code sample Restful Web Services With Jersey API
  5. The Jersey Spring Servlet is part of the jersey-spring.jar file which can be downloaded from the Jersey download site
  6. Finally, the following is the ant build file that I used.
    <project name="jerseyRest" default="compile" basedir=".">
        <property file="build.properties" />
        <property file="${user.home}/build.properties" />
        <property name="app.name" value="jerseyRest" />
        <property name="app.path" value="/${app.name}" />
        <property name="app.version" value="0.1-dev" />
        <property name="build.home" value="${basedir}/build" />
        <property name="catalina.home" value="c:/tomcat7" />
        <property name="dist.home" value="${basedir}/dist" />
        <property name="docs.home" value="${basedir}/docs" />
        <property name="manager.url" value="http://localhost:8080/manager/text" />
        <property name="manager.username" value="tomcat" />
        <property name="manager.password" value="tomcat" />
        <property name="src.home" value="${basedir}/src" />
        <property name="web.home" value="${basedir}/WebContent" />
        <path id="compile.classpath">
            <fileset dir="${catalina.home}/bin">
                <include name="*.jar" />
            </fileset>
            <pathelement location="${catalina.home}/lib" />
            <fileset dir="${catalina.home}/lib">
                <include name="*.jar" />
            </fileset>
            <fileset dir="${web.home}/WEB-INF/lib">
                <include name="*.jar" />
            </fileset>
    
        </path>
        <taskdef resource="org/apache/catalina/ant/catalina.tasks" classpathref="compile.classpath" />
        <taskdef name="deploy" classname="org.apache.catalina.ant.DeployTask" classpathref="compile.classpath" />
        <taskdef name="list" classname="org.apache.catalina.ant.ListTask" classpathref="compile.classpath" />
        <taskdef name="reload" classname="org.apache.catalina.ant.ReloadTask" classpathref="compile.classpath" />
        <taskdef name="findleaks" classname="org.apache.catalina.ant.FindLeaksTask" classpathref="compile.classpath" />
        <taskdef name="resources" classname="org.apache.catalina.ant.ResourcesTask" classpathref="compile.classpath" />
        <taskdef name="start" classname="org.apache.catalina.ant.StartTask" classpathref="compile.classpath" />
        <taskdef name="stop" classname="org.apache.catalina.ant.StopTask" classpathref="compile.classpath" />
        <taskdef name="undeploy" classname="org.apache.catalina.ant.UndeployTask" classpathref="compile.classpath" />
    
        <property name="compile.debug" value="true" />
        <property name="compile.deprecation" value="false" />
        <property name="compile.optimize" value="true" />
    
    
        <target name="all" depends="clean,compile" description="Clean build and dist directories, then compile" />
    
        <target name="clean" description="Delete old build and dist directories">
            <delete dir="${build.home}" />
            <delete dir="${dist.home}" />
        </target>
    
    
        <target name="compile" depends="prepare" description="Compile Java sources">
            <mkdir dir="${build.home}/WEB-INF/classes" />
            <javac srcdir="${src.home}" destdir="${build.home}/WEB-INF/classes" debug="${compile.debug}" deprecation="${compile.deprecation}" optimize="${compile.optimize}">
                <classpath refid="compile.classpath" />
            </javac>
            <copy todir="${build.home}/WEB-INF/classes">
                <fileset dir="${src.home}" excludes="**/*.java" />
            </copy>
        </target>
    
        <target name="dist" depends="compile,javadoc" description="Create binary distribution">
            <mkdir dir="${dist.home}/docs" />
            <copy todir="${dist.home}/docs">
                <fileset dir="${docs.home}" />
            </copy>
            <jar jarfile="${dist.home}/${app.name}-${app.version}.war" basedir="${build.home}" />
        </target>
    
    
        <target name="install" depends="compile" description="Install application to servlet container">
            <deploy url="${manager.url}" username="${manager.username}" password="${manager.password}" path="${app.path}" localWar="file://${build.home}" />
        </target>
    
    
        <target name="javadoc" depends="compile" description="Create Javadoc API documentation">
            <mkdir dir="${dist.home}/docs/api" />
            <javadoc sourcepath="${src.home}" destdir="${dist.home}/docs/api" packagenames="*">
                <classpath refid="compile.classpath" />
            </javadoc>
        </target>
    
    
    
        <target name="list" description="List installed applications on servlet container">
            <list url="${manager.url}" username="${manager.username}" password="${manager.password}" />
        </target>
    
    
        <target name="prepare">
            <mkdir dir="${build.home}" />
            <mkdir dir="${build.home}/WEB-INF" />
            <mkdir dir="${build.home}/WEB-INF/classes" />
            <copy todir="${build.home}">
                <fileset dir="${web.home}" />
            </copy>
            <mkdir dir="${build.home}/WEB-INF/lib" />
        </target>
    
        <target name="reload" depends="compile" description="Reload application on servlet container">
            <reload url="${manager.url}" username="${manager.username}" password="${manager.password}" path="${app.path}" />
        </target>
        <target name="remove" description="Remove application on servlet container">
            <undeploy url="${manager.url}" username="${manager.username}" password="${manager.password}" path="${app.path}" />
        </target>
    </project>

Wednesday, July 29, 2009

Spring AOP with XML-based Configuration

The previous post described how to use AspectJ annotations to implement Spring AOP. However, many programmers prefer to put configuration outside code. In such case Spring support for AOP through XML declaration of AOP components comes in handy. In this post we'll see how the same application can be implemented using Schema-based AOP support in Spring. An example of using pointcuts method parameters is also shown. Here's the code, followed by the explanations.

The Simple application ...
  • Search Engine Interface :
    /*
    * Author: Abhi Vuyyuru
    */
    package search;

    import java.util.List;

    public interface SearchEngine {
    public List<String> search(String prefix);
    }
    SearchEngine.java
  • Search Engine Class :
    /*
    * Author: Abhi Vuyyuru
    */
    package search;

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

    public class SearchEngineImpl implements SearchEngine {

    public List<String> search(String prefix) {
    System.out.println("In search implementation");
    List<String> list =
    new ArrayList<String>();
    list.add
    (prefix + " result 1");
    list.add
    (prefix + " result 2");
    return list;
    }

    }
    SearchEngineImpl.java
  • Main method:
    /*
    * Author: Abhi Vuyyuru
    */
    package main;

    import java.util.List;

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

    import search.SearchEngine;

    public class AopTest {

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

    SearchEngine searchEngine =
    (SearchEngine) ctx.getBean("searchEngine");
    List<String> searchResults = searchEngine.search
    ("search");
    System.out.println
    ("Number of results : " + searchResults.size());

    }
    }
    AopTest.java
Spring AOP classes and configuration
  • Appication Conext : This the spring configuration file for the example.
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    &nbspxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    &nbspxmlns:tx="http://www.springframework.org/schema/tx"
    &nbspxsi:schemaLocation="
    &nbsphttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    &nbsphttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
    &nbsphttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
    <!--
    <aop:aspectj-autoproxy proxy-target-class="true"/> <bean
    &nbspid="adviceObject" class="aop.AspectJAdvice" />
    &nbsp-->
    <aop:config>
    <!-- Pointcut for every method invocation -->
    <aop:pointcut id="searchEnginePc" expression="execution(* *(..))" />

    <!-- Pointcut for every method invocation with a String parameter -->
    <aop:pointcut id="pointcutWithParam" expression="execution(* *(..)) and args(prefix)" />

    <!-- After returning advice -->
    <aop:aspect id="springAspect" ref="adviceObject">

    <aop:around pointcut-ref="searchEnginePc" method="aroundAdvice" />

    <aop:after-returning pointcut-ref="searchEnginePc"
    &nbspmethod="afterAdvice" />

    <aop:before pointcut-ref="pointcutWithParam" method="beforeAdvice" />

    </aop:aspect>
    </aop:config>

    <bean id="adviceObject" class="aop.SpringAdvice" />
    <bean id="searchEngine" class="search.SearchEngineImpl" />
    </beans>
    applicationContext.xml
    • This xml is used for the default Spring AOP implementation with Java dynamic proxies. Note that the main method is programmed to the SearchEngine interface rather than the concrete class.
      SearchEngine searchEngine = (SearchEngine) ctx.getBean("searchEngine");
      Hence, the AOP configuration was set to
      <aop:config >
      If you have to use the concrete class in your application, as shown below
      SearchEngineImpl searchEngine = (SearchEngineImpl) ctx.getBean("searchEngine");
      You have to change the AOP configuration to the following
      <!-- proxy-target-class forces the use of CGLIB proxies, which allows proxying classes in addition to interfaces.-->
      <aop:config proxy-target-class="true">
      This will force the use of CGLIB proxies which allow proxying concrete classes too.
    • The aop-config element defines three different types of advice, around-advice, before advice, and after return advice.
      • Before Advice: Applied before a join point. This does not have the ability to prevent jointpoint (method execution) unless it throws an exception. The Before advice in the example uses a pointcut that uses arguments and can be used as a model for applying Advice for methods based on the parameter passed to the methods.
      • After Return Advice: Applied after the join points returns without exception.
      • Around Advice: Is applied around a join point. Note that the around advice is NOT called "before and after" the join point, but rather "around" the join point. If you look at the code below, the around advice is invoked when the join point is about to execute, but the around advice takes control of the execution. If you do not call the pjp.proceed() method in the following code, the join point will not be invoked.
        /*
        * Applied around a any public method.
        */
        public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("Around advice before joinpoint");
        Object obj = pjp.proceed
        ();
        System.out.println
        ("Around advice after running");
        return obj;
        }
        Around advice has the ability to change the behavior of the join point, and even to stop the join point execution.
    • The Aspect:
    /*
    * Author: Abhi Vuyyuru
    */
    package aop;

    import org.aspectj.lang.ProceedingJoinPoint;

    public class SpringAdvice {
    /*
    * Applied around a any public method, based on XML configuration
    */
    public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("Around advice before joinpoint");
    Object obj = pjp.proceed
    ();
    System.out.println
    ("Around advice after running");
    return obj;
    }

    /*
    * Applied before the execution of any method which takes a String argument.
    * Based on XML configuration
    */
    public void beforeAdvice(String prefix) {
    System.out.println("Before advice : " + prefix);
    }

    /*
    * Applied after returning, based on XML configuration
    */
    public void afterAdvice() {
    System.out.println("After Returning advice");
    }



    }
    AspectJAdvice.java

Tuesday, July 28, 2009

Spring AOP with AspectJ Annotations

This post describes how to use Spring AOP with AspectJ aspects using AspectJ annotations. An example of using pointcuts method parameters is also shown. I assume that you are familiar with the basic AOP concepts, however, here are a couple of things that you must to know if you are new to AOP.
  • Cross-cutting concerns: Any part of the application that has implications through most of the major modules of the application may be termed as a cross-cutting concern. Coding such cross-cutting concerns into the business methods will not only increase code-complexity but also reduce re-usability. Application security and transaction management are the best examples of cross-cutting concerns.
  • Aspect: An aspect is the "unit of modularity" of any of the cross-cutting concerns within the applications. In Spring AOP, aspects are implemented using regular Java class
    • with annotations AspectJ is enabled
    • declaratively, without annotations, in the application context.
  • Join point and pointcut: join point is any point during the program execution of a program, such as the execution of a method or the handling of an exception. Spring AOP only supports methods as join points. A pointcut is a predicate which is used to identify join points.
  • Advice: Action applied at join points. Advice can be applied before, after or around a join point. In Spring, advice is modeled as an interceptor. Multiple advices hare maintained as a chain of intercptors around the join point.
One important thing to note here is that, by default, Spring uses Java Dynamic Proxies to implement Aspect Oriented Programming support. This requires you to "program to interfaces rather than classes" which is anyway a good programming practice. But if you have to code to concrete classes, you can force Spring AOP to use CGLIB proxies. How to do so is explained with the example. For an in-depth understanding of AOP concepts, refer to either AspectJ and/or Spring AOP documentation. Here's the code, followed by the explanations.

The Simple application ...
  • Search Engine Interface :
    /*
    * Author: Abhi Vuyyuru
    */
    package search;

    import java.util.List;

    public interface SearchEngine {
    public List<String> search(String prefix);
    }
    SearchEngine.java
  • Search Engine Class :
    /*
    * Author: Abhi Vuyyuru
    */
    package search;

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

    public class SearchEngineImpl implements SearchEngine {

    public List<String> search(String prefix) {
    System.out.println("In search implementation");
    List<String> list =
    new ArrayList<String>();
    list.add
    (prefix + " result 1");
    list.add
    (prefix + " result 2");
    return list;
    }

    }
    SearchEngineImpl.java
  • Main method:
    /*
    * Author: Abhi Vuyyuru
    */
    package main;

    import java.util.List;

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

    import search.SearchEngine;

    public class AopTest {

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

    SearchEngine searchEngine =
    (SearchEngine) ctx.getBean("searchEngine");
    List<String> searchResults = searchEngine.search
    ("search");
    System.out.println
    ("Number of results : " + searchResults.size());

    }
    }
    AopTest.java
Spring AOP classes and configuration
  • Appication Conext : This the spring configuration file for the example.
    <?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"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
    <!--Enables AspectJ auto-proxying-->
    <aop:aspectj-autoproxy />
    <bean id="adviceObject" class="aop.AspectJAdvice" />
    <bean id="searchEngine" class="search.SearchEngineImpl" />
    </beans>
    applicationContext.xml
    This xml is used for the default Spring AOP implementation with Java dynamic proxies. Note that the main method is programmed to the SearchEngine interface rather than the concrete class.
    SearchEngine searchEngine = (SearchEngine) ctx.getBean("searchEngine");

    Hence, the AOP configuration was set to
    <aop:aspectj-autoproxy />
    If you have to use the concrete class in your application, as shown below
    SearchEngineImpl searchEngine = (SearchEngineImpl) ctx.getBean("searchEngine");

    You have to change the AOP configuration to the following
    <!-- proxy-target-class forces the use of CGLIB proxies, which allows proxying classes in addition to interfaces.-->
    <aop:aspectj-autoproxy proxy-target-class="true" />
    This will force the use of CGLIB proxies which allow proxying concrete classes too.
  • The Aspect: This aspect defines a pointcut and three different types of advice, around-advice, before advice, and after return advice.
    • Before Advice: Applied before a join point. This does not have the ability to prevent jointpoint (method execution) unless it throws an exception.
    • After Return Advice: Applied after the join points returns without exception.
    • Around Advice: Is applied around a join point. Note that the around advice is NOT called "before and after" the join point, but rather "around" the join point. If you look at the code below, the around advice is invoked when the join point is about to execute, but the around advice takes control of the execution. If you do not call the pjp.proceed() method in the following code, the join point will not be invoked.
      /*
      * Applied around a any public method.
      */
      @Around("execution(public * *(..))")
      public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
      System.out.println("Around advice before joinpoint");
      Object obj = pjp.proceed
      ();
      System.out.println
      ("Around advice after running");
      return obj;
      }
      Around advice has the ability to change the behavior of the join point, and even to stop the join point execution.
    /*
    * Author: Abhi Vuyyuru
    */
    package aop;

    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    @Aspect
    public class AspectJAdvice {

    /*
    * Applied around a any public method.
    */
    @Around("execution(public * *(..))")
    public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("Around advice before joinpoint");
    Object obj = pjp.proceed
    ();
    System.out.println
    ("Around advice after running");
    return obj;
    }

    /*
    * Applied before the execution of any method which takes a String argument.
    */
    @Before("execution(* *(..)) &&" + "args(prefix)")
    public void beforeAdvice(String prefix) {
    System.out.println("Before advice : " + prefix);
    }

    /*
    * Applied after returning from the pointcut defined by anyPublicMethod
    */
    @AfterReturning("anyPublicMethod()")
    public void afterAdvice() {
    System.out.println("After Returning advice");
    }

    /*
    * Defines a pointcut that matches any public method.
    */
    @Pointcut("execution(public * *(..))")
    private void anyPublicMethod() {
    }

    }
    AspectJAdvice.java
    • The pointcut here simply explains how a pointcut can be used instead of using predicates in the Advice annotations. Pointcuts come in handy when the advice predicates become too complex, in which case multiple pointcuts can be combined to form the proper predicate for matching the join point.
    • The Before advice in the example uses a predicate that uses arguments and can be used as a model for applying Advice for methods based on the parameter passed to the methods.

Thursday, April 17, 2008

Integrating Spring and Hibernate: Transactions

In the previous post, I described different ways in which spring and hibernate can
be integrated. In this post I will describe how to use Spring's transaction features
in hibernate. The following methods of transaction management with spring and hibernate are discussed.
  1. Declarative Transaction Mangement with AOP Interceptors
  2. Schema-based Declarative Transaction Management
  3. Schema-based Declarative Transaction Management with Annotations
  4. Programmatic Transaction Management

The easiest way to check if transactions are working for this example is to remove the transaction declarations for the getStockQuote() method. Removing transactions will cause the following exception
org.hibernate.LazyInitializationException: could not initialize proxy - no Session

There's More ...
For this example, start off with the following as described in the "Integrating Spring and Hibernate" post.
  1. The bean StockQuoteBean
  2. The Portfolio classes : PortfolioDAO, PortfolioDAOSupport and PortfolioDAOTemplate
  3. The hibernate mapping file stockquote.hbm.xml

The following main class can be used:
package springhibernate;


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


public class SpringHibernateTest {


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

IPortfolioService portfolioService = (IPortfolioService) ctx.getBean("portfolioService");
System.out.println("Portfolio Service type : " + portfolioService.getClass());
portfolioService.getStockQuote("123");
}


}
SpringHibernateTest.java

Note that here we use an Interface IPortfolioService, and also note the change to ApplicationContext instead of a BeanFactory.
The reason for using ApplicationContext is enable the use of AOP for declarative transaction management. Also we are not expecting any return to the main class as all the execution is expected to happen in the transaction context.

The Portfolio Service Interface:
package springhibernate;

import beans.StockQuoteBean;

public interface IPortfolioService {

public void getStockQuote(String id);

public void updateStockQuote(StockQuoteBean stockQuoteBean);

}
IPortfolioService.java

Declarative Transaction Management

Declarative transaction management in Spring has the advantage of being less invasive. There is no need for changing application code when using declarative transactions. All you have to do is to modify the application context.

The Service class will be same for all the modes of Declarative transaction management described below.
package springhibernate;

import beans.StockQuoteBean;
import dao.PortfolioDAO;


public class PortfolioService implements IPortfolioService {
private PortfolioDAO portfolioDAO;



public void getStockQuote(String id) {
StockQuoteBean result = portfolioDAO.getStockQuote(id);
System.out.println("Result in Service : " + result.getStockSymbol());

}

public void updateStockQuote(StockQuoteBean stockQuoteBean) {
portfolioDAO.updateStockQuote(stockQuoteBean);
}

public PortfolioDAO getPortfolioDAO() {
return portfolioDAO;
}

public void setPortfolioDAO(PortfolioDAO portfolioDAO) {
this.portfolioDAO = portfolioDAO;
System.out.println("Setting portfolio DAO to : " + portfolioDAO.getClass());
}

}
PortfolioService.java

Declarative Transaction Management with AOP Interceptor

In this method, you have to define a proxy for the bean that will be made transactional.
<?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"
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">

<bean id="portfolioDAOTemplate" class="dao.PortfolioDAOTemplate">
<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>

<bean id="portfolioDAOSupport" class="dao.PortfolioDAOSupport">
<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>

<bean id="myPortfolioService" class="springhibernate.PortfolioService">
<property name="portfolioDAO" ref="portfolioDAOTemplate"></property>
</bean>

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

<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributeSource">
<value>springhibernate.PortfolioService.*=PROPAGATION_REQUIRED</value>
</property>
</bean>

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

<bean id="portfolioService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="myPortfolioService"></property>
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
<value>hibernateInterceptor</value>
</list>
</property>
</bean>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@localhost:1521/xe" />
<property name="username" value="appUser" />
<property name="password" value="password" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>stockquote.hbm.xml</value>
</list>
</property>

<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.generate_statistics">true</prop>
</props>
</property>
</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

</beans>
applicationContext.xml

Note that the transactionInterceptor and hibernateTransactionInterceptor are declared. While transactionInterceptor is used to set the transaction properties, the hibernateTransactionInterceptor will manage the hibernate transactions.

Schema-based Declarative Transaction Management

<?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"
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">

<bean id="portfolioDAOTemplate" class="dao.PortfolioDAOTemplate">
<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>

<bean id="portfolioDAOSupport" class="dao.PortfolioDAOSupport">
<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>

<bean id="portfolioService" class="springhibernate.PortfolioService">
<property name="portfolioDAO" ref="portfolioDAOTemplate"></property>
</bean>

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

<aop:config>
<aop:pointcut id="serviceMethods" expression="execution(* springhibernate.IPortfolioService.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods" />
</aop:config>

<tx:advice id="txAdvice" transaction-manager="transactionManager" >
<tx:attributes>
<tx:method name="*" propagation="REQUIRES_NEW" />
</tx:attributes>
</tx:advice>


<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@localhost:1521/xe" />
<property name="username" value="appUser" />
<property name="password" value="password" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>stockquote.hbm.xml</value>
</list>
</property>

<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.generate_statistics">true</prop>
</props>
</property>
</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

</beans>
applicationContext.xml
Using Schema-based declarative transaction management is a lot simpler and a lot cleaner. However it is adviced that this method not be used in conjunction with explicit auto-proxying using BeanNameAutoProxyCreator, as it might raise issues like advice not being woven etc. Note that the AOP pointcut is defined to be all methods on the IPortfolioService inteface.

Schema-based Declarative Transaction Management with Annotations

<?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"
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">

<bean id="portfolioDAOTemplate" class="dao.PortfolioDAOTemplate">
<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>

<bean id="portfolioDAOSupport" class="dao.PortfolioDAOSupport">
<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>

<bean id="portfolioService" class="springhibernate.PortfolioService">
<property name="portfolioDAO" ref="portfolioDAOTemplate"></property>
</bean>

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

<tx:annotation-driven/>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@localhost:1521/xe" />
<property name="username" value="appUser" />
<property name="password" value="password" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>stockquote.hbm.xml</value>
</list>
</property>

<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.generate_statistics">true</prop>
</props>
</property>
</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

</beans>
applicationContext.xml
When using annotations, you only have to declare the transaction manager and add <tx:annotation-driven/> to the application context. If the transaction manager is named "transactionManager" then you don't have to declare a transaction-manager attribute for <tx:annotation-driven/> as it happens to be the default value for that attribute.
Also we have to declare the pointcuts in the Service class itself. Note that as annotations are not inherited, declaring the annotations has to be done at the class level.
@Transactional
public class PortfolioService implements IPortfolioService {
private PortfolioDAO portfolioDAO;...

Programmatic Transaction Management

For programmatic transaction management in spring, you will need a PlatformTransctionManger in your bean which will be used to create a TransactionTemplate. The TransactionTemplate is used in the same way the HibernateTemplate was used in previous example. Additionally you will have to create a HibernateTransactionManager as shown in the above example.
package springhibernate;

import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import beans.StockQuoteBean;
import dao.PortfolioDAO;

public class PortfolioServiceTransaction implements IPortfolioService{
private PortfolioDAO portfolioDAO;

private PlatformTransactionManager transactionManager;

public void getStockQuote(final String id) {
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {

public void doInTransactionWithoutResult(TransactionStatus status) {
StockQuoteBean result = portfolioDAO.getStockQuote(id);
System.out.println("Symbol in transaction " + result.getStockSymbol());
}
});

}

public void updateStockQuote(final StockQuoteBean stockQuoteBean) {
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {

public void doInTransactionWithoutResult(TransactionStatus status) {
portfolioDAO.updateStockQuote(stockQuoteBean);
}
});

}

public PortfolioDAO getPortfolioDAO() {
return portfolioDAO;
}

public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}

public void setPortfolioDAO(PortfolioDAO portfolioDAO) {
this.portfolioDAO = portfolioDAO;
System.out.println("Setting portfolio DAO to : " + portfolioDAO.getClass());
}

}
PortfolioService.java

Monday, April 14, 2008

Integrating Spring and Hibernate

This post applies to integrating Spring framework 2.5.3 and Hibernate 3.0.

The Spring framework provides extensive support for data access through the use of support classes (JdbcDaoSupport, JdbcTemplate etc.), and extensive exception hierarchy to wrap any platform specific SQLException into an exception in the spring exception hierarchy. Additionally Spring framework also provides good support for integrating with ORM technologies like Hibernate and iBatis etc. This post will show how to integrate Spring framework with Hibernate ORM. There's more ...
  1. Create the bean: The bean here represents a simple stock quote
    package beans;

    public class StockQuoteBean {
    private String quoteId;

    private String stockSymbol;

    private String name;

    public String getQuoteId() {
    return quoteId;
    }

    public void setQuoteId(String quoteId) {
    this.quoteId = quoteId;
    }

    public String getStockSymbol() {
    return stockSymbol;
    }

    public void setStockSymbol(String stockSymbol) {
    this.stockSymbol = stockSymbol;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }
    }
    StockQuoteBean.java
  2. Create a Hibernate Mapping file for the bean:
    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
    <class name="beans.StockQuoteBean" table="STOCK_QUOTES" lazy="false">
    <id name="quoteId" column="quote_id">
    <generator class="assigned" />
    </id>

    <property name="stockSymbol">
    <column name="stock_symbol" />
    </property>
    <property name="name">
    <column name="name" />
    </property>
    </class>
    </hibernate-mapping>
    stockquote.hbm.xml

    The one important thing to note here is that in the declaration, a [lazy="false"] has been added to the mapping for the stockquote bean. The reason for this is that in hibernate 3, lazy initialization is turned on by default. This raises a problem when used with spring's HibernateCallback. The spring HibernateTemplate.execute() by default closes any open sessions upon completion. When used with lazy initialization you may get a LazyInitializationException like the following
    org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    If you want to use lazy initialization with HibernateCallback, you will have to use this within a transaction context. The javadoc for HibernateTemplate specifies this explicitly
    Note that operations that return an Iterator (i.e. iterate) are supposed
    to be used within Spring-driven or JTA-driven transactions (with
    HibernateTransactionManager, JtaTransactionManager, or EJB CMT). Else, the
    Iterator won't be able to read results from its ResultSet anymore, as the
    underlying Hibernate Session will already have been closed.

    Lazy loading will also just work with an open Hibernate Session, either within a
    transaction or within OpenSessionInViewFilter/Interceptor. Furthermore, some
    operations just make sense within transactions, for example: contains, evict,
    lock, flush, clear.
  3. The service class: The service class simply acts as an intermediary between the client and the DAO classes.
    package springhibernate;

    import beans.StockQuoteBean;
    import dao.PortfolioDAO;

    public class PortfolioService {
    private PortfolioDAO portfolioDAO;

    public StockQuoteBean getStockQuote(String id) {
    StockQuoteBean result = portfolioDAO.getStockQuote(id);
    return result;
    }

    public void updateStockQuote(StockQuoteBean stockQuoteBean) {
    portfolioDAO.updateStockQuote(stockQuoteBean);
    }

    public PortfolioDAO getPortfolioDAO() {
    return portfolioDAO;
    }

    public void setPortfolioDAO(PortfolioDAO portfolioDAO) {
    this.portfolioDAO = portfolioDAO;
    System.out.println("Setting portfolio DAO to : " + portfolioDAO.getClass());
    }

    }
    PortfolioService.java
  4. The DAO interface:
    package dao;

    import beans.StockQuoteBean;

    public interface PortfolioDAO {
    public StockQuoteBean getStockQuote(String id);
    public void updateStockQuote(StockQuoteBean bean);
    public StockQuoteBean getStockQuote_hibernateTemplate(String id);
    public void updateStockQuote_hibernateTemplate(StockQuoteBean bean);
    }
    PortfolioDAO.java
  5. The DAO Classes: The DAO classes shows the different ways in which the Hibernate calls can be made using the Spring support classes. There are three primary ways in which these calls can be made
    1. Using the HibernateCallback
    2. Using the HibernateTemplate directly
    3. Using the hibernate native calls using Session
    Spring also provides two different ways to create the Data access objects that interact with Hibernate.
    1. Using Composition, with HibernateTemplate
    2. Using Inheritance by extending HibernateDaoSupport
    All these methods will be explained when used in the following sections.
    1. Using HibernateTemplate
      package dao;

      import java.sql.SQLException;
      import java.util.List;

      import org.hibernate.HibernateException;
      import org.hibernate.Session;
      import org.springframework.orm.hibernate3.HibernateCallback;
      import org.springframework.orm.hibernate3.HibernateTemplate;

      import beans.StockQuoteBean;

      public class PortfolioDAOTemplate implements PortfolioDAO{
      private HibernateTemplate hibernateTemplate;

      public PortfolioDAOTemplate() {
      System.out.println("Init transaction dao");
      }


      public StockQuoteBean getStockQuote(final String id) {

      HibernateCallback callback = new HibernateCallback() {
      public Object doInHibernate(Session session) throws HibernateException, SQLException {
      return session.load(StockQuoteBean.class, id);
      }
      };
      return (StockQuoteBean) hibernateTemplate.execute(callback);
      }

      public void updateStockQuote(final StockQuoteBean StockQuoteBean) {
      HibernateCallback callback = new HibernateCallback() {
      public Object doInHibernate(Session session) throws HibernateException, SQLException {
      session.saveOrUpdate(StockQuoteBean);
      return null;
      }
      };
      hibernateTemplate.execute(callback);

      }

      public void updateStockQuote_hibernateTemplate(StockQuoteBean StockQuoteBean) {
      hibernateTemplate.update(StockQuoteBean);

      }
      public StockQuoteBean getStockQuote_hibernateTemplate(String id) {
      List<StockQuoteBean> transactions = hibernateTemplate.find("from beans.StockQuoteBean stockQuoteBean where stockQuoteBean.quoteId=?", id);
      return transactions.get(0);
      }


      public HibernateTemplate getHibernateTemplate() {
      return hibernateTemplate;
      }


      public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
      this.hibernateTemplate = hibernateTemplate;
      }



      }
      PortfolioDAOTemplate

      This class shows how to use the HibernateTemplate to make calls to Hibernate. The getStockQuote() and updateStockQuote() methods use HibernateCallback class, note that when using HibernateCallback, it is necessary to either do it in a transactional context or turn off lazy initialization. While the getStockQuote_hibernateTemplate() and updateStockQuote_hibernateTemplate() make calls using hibernateTemplate directly. Also note that the parameters to the getStockQuote(), and updateStockQuote() methods are marked final.
    2. Using HibernateDaoSupport
      package dao;

      import java.util.List;

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

      import beans.StockQuoteBean;

      public class PortfolioDAOSupport extends HibernateDaoSupport implements PortfolioDAO {

      public void updateStockQuote(StockQuoteBean stockQuoteBean) {
      Query query = getSession().createQuery("update beans.StockQuoteBean set stockSymbol=? where quoteId=?");
      query.setString(0, stockQuoteBean.getStockSymbol());
      query.setString(1, stockQuoteBean.getQuoteId());
      query.executeUpdate();
      }
      public StockQuoteBean getStockQuote(String id) {
      Query query = getSession().createQuery("from beans.StockQuoteBean stockQuoteBean where stockQuoteBean.quoteId=?");
      query.setString(0, id);
      List results = query.list();
      if(results == null || results.size() == 0) {
      throw new RuntimeException("No result");
      }
      return (StockQuoteBean)results.get(0);
      }

      public void updateStockQuote_hibernateTemplate(StockQuoteBean StockQuoteBean) {
      getHibernateTemplate().update(StockQuoteBean);

      }
      public StockQuoteBean getStockQuote_hibernateTemplate(String id) {
      List<StockQuoteBean> transactions = getHibernateTemplate().find("from beans.StockQuoteBean stockQuoteBean where stockQuoteBean.quoteId=?", id);
      return transactions.get(0);
      }

      }
      PortfolioDAOSupport

      This class uses HibernateDaoSupport to get instances of HibernateTemplate, and the Hibernate Session. The getStockQuote() and updateStockQuote() in this class make calls to hibernate session directly.
  6. The application context
    <?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"
    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">

    <bean id="portfolioDAOTemplate" class="dao.PortfolioDAOTemplate">
    <property name="hibernateTemplate" ref="hibernateTemplate" />
    </bean>

    <bean id="portfolioDAOSupport" class="dao.PortfolioDAOSupport">
    <property name="hibernateTemplate" ref="hibernateTemplate" />
    </bean>

    <bean id="portfolioService" class="springhibernate.PortfolioService">
    <property name="portfolioDAO" ref="portfolioDAOSupport"></property>
    </bean>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
    <property name="url" value="jdbc:oracle:thin:@localhost:1521/xe" />
    <property name="username" value="appUser" />
    <property name="password" value="password" />
    </bean>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="mappingResources">
    <list>
    <value>stockquote.hbm.xml</value>
    </list>
    </property>

    <property name="hibernateProperties">
    <props>
    <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
    <prop key="hibernate.show_sql">true</prop>
    <prop key="hibernate.generate_statistics">true</prop>
    </props>
    </property>
    </bean>
    <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
    <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    </beans>
    applicationContext.xml
    • The SessionFactory is defined with the datasource and mapping-resources. The hibernate specific properties are defined under the hibernateProperties property.
    • The HibernateTemplate uses are reference to the SessionFactory.
    • The HibernateTemplate is used as a reference to the DAO classes.
    • The porfolioService bean in uses a reference to the PortfolioDAO, which can be switched between the dao.PortfolioDAOSupport and dao.PortfolioDAOTemplate beans
  7. The main class
    package springhibernate;


    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.xml.XmlBeanFactory;
    import org.springframework.core.io.FileSystemResource;
    import org.springframework.core.io.Resource;

    import beans.StockQuoteBean;


    public class SpringHibernateTest {


    public static void main(String[] args) {
    Resource resource = new FileSystemResource("applicationContext.xml");
    BeanFactory factory = new XmlBeanFactory(resource);

    PortfolioService portfolioService = (PortfolioService) factory.getBean("portfolioService");

    StockQuoteBean result = portfolioService.getStockQuote("123");
    System.out.println(result.getStockSymbol());

    empResult.setStockSymbol("GOOG");
    portfolioService.updateStockQuote(result);
    }


    }
    SpringHibernateTest.java
  8. Necessary JAR files:
    • commons-logging-1.1.1.jar
    • hibernate3.jar
    • dom4j-1.6.1.jar
    • ojdbc14.jar
    • commons-collections-3.2.jar
    • log4j-1.2.15.jar
    • commons-dbcp.jar
    • commons-pool.jar
    • spring.jar
    • cglib-nodep-2.1_3.jar
    • antlr-2.7.6.jar
    • jta.jar

Monday, August 20, 2007

Handling Security with Ajax, DWR and Acegi

This is an extension of a previous post that described how to secure your method calls using Acegi security. Here, I will go through how to secure your Asynchronous calls, using the same example with some modifications to include Ajax calls using Direct Web Remoting (DWR).
  1. Create the example project as shown in "Spring security with Acegi Security Framework". This will be the starting point.
  2. Create the SecureDAO object.
    package test;

    public class SecureDAO {
    public String create() {
    System.out.println("Create");
    return "create";
    }

    public String read() {
    System.out.println("read");
    return "read";
    }

    public String update() {
    System.out.println("update");
    return "update";
    }
    }
  3. Update the applicationContext.xml file to include the security definitions by adding the following bean definitions as shown below
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

    <beans>

    <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
    <property name="filterInvocationDefinitionSource">
    <value>
    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    PATTERN_TYPE_APACHE_ANT
    /**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
    </value>
    </property>
    </bean>

    <bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"/>

    <bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">
    <constructor-arg value="/index.jsp"/>
    <constructor-arg>
    <list>
    <ref bean="rememberMeServices"/>
    <bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>
    </list>
    </constructor-arg>
    </bean>

    <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
    <property name="authenticationManager" ref="authenticationManager"/>
    <property name="authenticationFailureUrl" value="/login.jsp?errorId=1"/>
    <property name="defaultTargetUrl" value="/"/>
    <property name="filterProcessesUrl" value="/j_acegi_security_check"/>
    <property name="rememberMeServices" ref="rememberMeServices"/>
    </bean>

    <bean id="securityContextHolderAwareRequestFilter" class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter"/>

    <bean id="rememberMeProcessingFilter" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
    <property name="authenticationManager" ref="authenticationManager"/>
    <property name="rememberMeServices" ref="rememberMeServices"/>
    </bean>

    <bean id="anonymousProcessingFilter" class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
    <property name="key" value="changeThis"/>
    <property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/>
    </bean>

    <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
    <property name="authenticationEntryPoint">
    <bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
    <property name="loginFormUrl" value="/login.jsp"/>
    <property name="forceHttps" value="false"/>
    </bean>
    </property>
    <property name="accessDeniedHandler">
    <bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
    <property name="errorPage" value="/denied.jsp"/>
    </bean>
    </property>
    </bean>

    <bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
    <property name="authenticationManager" ref="authenticationManager"/>
    <property name="accessDecisionManager">
    <bean class="org.acegisecurity.vote.AffirmativeBased">
    <property name="allowIfAllAbstainDecisions" value="false"/>
    <property name="decisionVoters">
    <list>
    <bean class="org.acegisecurity.vote.RoleVoter"/>
    <bean class="org.acegisecurity.vote.AuthenticatedVoter"/>
    </list>
    </property>
    </bean>
    </property>
    <property name="objectDefinitionSource">
    <value>
    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    PATTERN_TYPE_APACHE_ANT
    /secure/admin/**=ROLE_ADMIN
    /secure/**=IS_AUTHENTICATED_REMEMBERED
    /**=IS_AUTHENTICATED_ANONYMOUSLY
    </value>
    </property>
    </bean>

    <bean id="rememberMeServices" class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
    <property name="userDetailsService" ref="userDetailsService"/>
    <property name="tokenValiditySeconds" value="1800"></property>
    <property name="key" value="changeThis"/>
    </bean>

    <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
    <property name="providers">
    <list>
    <ref local="daoAuthenticationProvider"/>
    <bean class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
    <property name="key" value="changeThis"/>
    </bean>
    <bean class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
    <property name="key" value="changeThis"/>
    </bean>
    </list>
    </property>
    </bean>

    <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
    <property name="userDetailsService" ref="userDetailsService"/>
    <property name="userCache">
    <bean class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
    <property name="cache">
    <bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
    <property name="cacheManager">
    <bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
    </property>
    <property name="cacheName" value="userCache"/>
    </bean>
    </property>
    </bean>
    </property>
    </bean>

    <bean id="userDetailsService" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
    <property name="userProperties">
    <bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
    <property name="location" value="/WEB-INF/users.properties"/>
    </bean>
    </property>
    </bean>

    <bean id="loggerListener" class="org.acegisecurity.event.authentication.LoggerListener"/>

    <bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
    <property name="authenticationManager">
    <ref bean="authenticationManager" />
    </property>
    <property name="accessDecisionManager">
    <bean class="org.acegisecurity.vote.AffirmativeBased">
    <property name="allowIfAllAbstainDecisions" value="false" />
    <property name="decisionVoters">
    <list>
    <bean class="org.acegisecurity.vote.RoleVoter" />
    <bean class="org.acegisecurity.vote.AuthenticatedVoter" />
    </list>
    </property>
    </bean>
    </property>
    <property name="objectDefinitionSource">
    <value>
    test.SecureDAO.*=IS_AUTHENTICATED_REMEMBERED
    test.SecureDAO.u=ROLE_ADMIN
    </value>
    </property>
    </bean>


    <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="interceptorNames">
    <list>
    <value>methodSecurityInterceptor</value>
    </list>
    </property>
    <property name="beanNames">
    <list>
    <value>secureDAO</value>
    </list>
    </property>
    </bean>

    <bean id="secureDAO" class="test.SecureDAO" />
    </beans>
  4. Update the Web deployment descriptor to forward DWR requests to the DWR Servlet
    <?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>DWRSpring</display-name>
    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
    <display-name>SpringListener</display-name>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <filter>
    <filter-name>Acegi Filter Chain Proxy</filter-name>
    <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
    <init-param>
    <param-name>targetClass</param-name>
    <param-value>org.acegisecurity.util.FilterChainProxy</param-value>
    </init-param>
    </filter>

    <filter-mapping>
    <filter-name>Acegi Filter Chain Proxy</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    <servlet>
    <servlet-name>dwr-invoker</servlet-name>
    <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
    <init-param>
    <param-name>debug</param-name>
    <param-value>true</param-value>
    </init-param>
    </servlet>

    <servlet-mapping>
    <servlet-name>dwr-invoker</servlet-name>
    <url-pattern>/dwr/*</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
    </web-app>

  5. In the DWR configuration file, set the creator to Spring
    <!DOCTYPE dwr PUBLIC
    "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
    "http://www.getahead.ltd.uk/dwr/dwr10.dtd">
    <dwr>
    <allow>
    <convert match="java.lang.Exception" converter="exception"/>
    <create creator="spring" javascript="secureDAO">
    <param name="beanName" value="secureDAO"/>
    </create>
    </allow>
    </dwr>
    Note:
    • The converter is used to convert the Java exception to Javascript exception.
  6. The main change will be made to the secure/authenticatedusers.jsp file. This will use DWR to make Ajax requests. Here is the code for the file
    <%@ page import="org.acegisecurity.context.SecurityContextHolder"%>
    <html>
    <head>

    <script type='text/javascript' src='/DWRSpring/dwr/interface/secureDAO.js'></script>
    <script type="text/javascript" src="../dwr/engine.js"> </script>
    <script type="text/javascript" src="../dwr/util.js"> </script>
    <script>
    dwr.engine.setErrorHandler(errorHandlerFn);
    function update() {
    var name = dwr.util.getValue("method");
    switch(name) {
    case "create":
    secureDAO.create(callBackFn)
    break;
    case "read":
    secureDAO.read(callBackFn);
    break;
    case "update":
    secureDAO.update(callBackFn);
    break;
    }

    }

    function callBackFn(str) {
    dwr.util.setValue("selectedAction","Server Returned : " + str);
    }

    function errorHandlerFn(message, exception) {
    dwr.util.setValue("selectedAction", "Error : " + message);
    }
    </script>

    </head>
    <body>
    <h1>Welcome: <%=SecurityContextHolder.getContext().getAuthentication().getName()%></h1>
    <p><a href="../">Home</a>
    <form name="testForm" action=""><select name="method" onchange="update()">
    <option value=""></option>
    <option value="create">create</option>
    <option value="read">read</option>
    <option value="update">update</option>
    </select></form>

    <div id="selectedAction"></div>
    <p><a href="../j_acegi_logout">Logout</a></p>
    </body>
    </html>
    Note:
    • The classes that are exposed through DWR will be available through the /WEB_APP_NAME/dwr/interface/JAVASCRIPT_NAME.js files.
      <script type='text/javascript' src='/DWRSpring/dwr/interface/secureDAO.js'></script>
    • The setErrorhandler call sets the global error handling function.
      dwr.engine.setErrorHandler(errorHandlerFn);
      Alternatively, the error handling function can be set for individual method calls (as described in DWR documentationa
      Remote.method(params, {
      callback:function(data) { ... },
      errorHandler:function(errorString, exception) { ... }
      });
    • util.js file contains utility functions for getting and setting values for the document elements.
  7. Make sure you have the following Jar files in your classpath:
    • acegi-security-1.0.3.jar
    • ant-junit.jar
    • cglib-nodep-2.1_3.jar
    • commons-codec-1.3.jar
    • commons-logging.jar
    • dwr.jar
    • ehcache-1.2.3.jar
    • jstl.jar
    • spring.jar
    • standard.jar

Popular Posts