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

Thursday, October 02, 2014

Transaction management - Spring Framework

Local vs. Global Transactions
Local transactions are specific to a single transactional resource like a JDBC connection, whereas global transactions can span multiple transactional resources like transaction in a distributed system.

Local transaction management can be useful in a centralized computing environment where application components and resources are located at a single site, and transaction management only involves a local data manager running on a single machine. Local transactions are easier to be implemented.

Global transaction management is required in a distributed computing environment where all the resources are distributed across multiple systems. In such a case transaction management needs to be done both at local and global levels. A distributed or a global transaction is executed across multiple systems, and its execution requires coordination between the global transaction management system and all the local data managers of all the involved systems.

Programmatic transaction management: This means that you have manage the transaction with the help of programming. That gives you extreme flexibility, but it is difficult to maintain.

Declarative transaction management: This means you separate transaction management from the business code. You only use annotations or XML based configuration to manage the transactions.

A transaction attribute may have one of the following values:
Required
RequiresNew
Mandatory
NotSupported
Supports
Never

Transaction Isolation level
DEFAULT This is the default isolation level.
READ_COMMITTED Indicates that dirty reads are prevented; non-repeatable reads and phantom reads can occur.
READ_UNCOMMITTED Indicates that dirty reads, non-repeatable reads and phantom reads can occur.
REPEATABLE_READ Indicates that dirty reads and non-repeatable reads are prevented; phantom reads can occur.
SERIALIZABLE Indicates that dirty reads, non-repeatable reads and phantom reads are prevented.

Spring.xml for hibernate
<beans xmlns="http://www.springframework.org/schema/beans"

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

    <!-- Enable Annotation based Declarative Transaction Management -->
    <tx:annotation-driven proxy-target-class="true"
        transaction-manager="transactionManager" />

    <!-- Creating TransactionManager Bean, since JDBC we are creating of type
        DataSourceTransactionManager -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
   
    <!-- MySQL DB DataSource -->
    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">

        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/TestDB" />
        <property name="username" value="pankaj" />
        <property name="password" value="pankaj123" />
    </bean>

    <bean id="customerDAO" class="com.journaldev.spring.jdbc.dao.CustomerDAOImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean id="customerManager" class="com.journaldev.spring.jdbc.service.CustomerManagerImpl">
        <property name="customerDAO" ref="customerDAO"></property>
    </bean>

</beans>



import org.springframework.transaction.annotation.Transactional;

import com.journaldev.spring.jdbc.dao.CustomerDAO;
import com.journaldev.spring.jdbc.model.Customer;

public class CustomerManagerImpl implements CustomerManager {

    private CustomerDAO customerDAO;

    public void setCustomerDAO(CustomerDAO customerDAO) {
        this.customerDAO = customerDAO;
    }

    @Override
    @Transactional
    public void createCustomer(Customer cust) {
        customerDAO.create(cust);
    }

}



Spring transactions client driver

package com.journaldev.spring.jdbc.main;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.journaldev.spring.jdbc.model.Address;
import com.journaldev.spring.jdbc.model.Customer;
import com.journaldev.spring.jdbc.service.CustomerManager;
import com.journaldev.spring.jdbc.service.CustomerManagerImpl;

public class TransactionManagerMain {

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

        CustomerManager customerManager = ctx.getBean("customerManager",
                CustomerManagerImpl.class);

        Customer cust = createDummyCustomer();
        customerManager.createCustomer(cust);

        ctx.close();
    }

    private static Customer createDummyCustomer() {
        Customer customer = new Customer();
        customer.setId(2);
        customer.setName("Pankaj");
        Address address = new Address();
        address.setId(2);
        address.setCountry("India");
        // setting value more than 20 chars, so that SQLException occurs
        address.setAddress("Albany Dr, San Jose, CA 95129");
        customer.setAddress(address);
        return customer;
    }

}

Annotation style transaction
To use the annotation style transaction management all you have to do is to add a 3 simple bean configuration in your xml file i.e:

<context:annotation-config/>: Tells Spring framework to read @Transactional annotation

<tx:annotation-driven/>: Automatically adds transaction support which eventually wraps your code in transaction scope
Initializing DataSourceTransactionManager bean


Example:
@Transactional
public class AnnotatedUserDao implements IUserDao {

Example for read only:
@Transactional(readOnly = true)
public User selectUser(int uid) {

Programmatic transactions in Spring
public void deleteUser(final int uid) {
 DefaultTransactionDefinition paramTransactionDefinition = new    DefaultTransactionDefinition();

  TransactionStatus status=platformTransactionManager.getTransaction(paramTransactionDefinition );
try{
  String delQuery = "delete from users where id = ?";
  jdbcTemplate.update(delQuery, new Object[]{uid});
  platformTransactionManager.commit(status);
}catch (Exception e) {
  platformTransactionManager.rollback(status);
}



Monday, July 01, 2013

JAX-RS Spring JPA Hibernate Maven web application

1. Workspace directory structure
C:\workspace\FFWD_NO_EJB>tree
Folder PATH listing
Volume serial number is 1C03-D338
C:.
├───.settings
├───src
│   └───main
│       ├───java
│       │   └───com
│       │       └───persistent
│       │           ├───entity
│       │           │   └───util
│       │           ├───rest
│       │           └───service
│       ├───resources
│       │   └───META-INF
│       └───webapp
│           └───WEB-INF
└───target

2. Entity java class
package com.persistent.entity;


import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;


@Entity
@XmlRootElement
@Table(name="AUTH_STAT")
public class Status implements Serializable {

    @Id
    @Column(name="AUTH_STAT_CD")
    private String statusCode;

    @Column(name = "AUTH_STAT_DSC")
    private String statusDescr;

    @Column(name = "AUTH_SEREVITY_ID")
    private Integer severity;

    @Column(name = "CREATE_TS")
    private Date createTimestamp;

    @Column(name = "CREATE_USER_ID")
    private String createUserId;

    @Column(name = "UPD_USER_ID")
    private String updUserId;

    @Column(name = "UPD_TS")
    private Date updTimestamp;


3. REST service Impl (create a service interface too)

ackage com.persistent.rest;


import java.util.List;
import java.util.StringTokenizer;

import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.persistent.entity.Status;
import com.persistent.service.StatusService;

// The Java class will be hosted at the URI path "/persons"

@Component
@Path("/status")
public class StatusResourceWs implements StatusResource {
    @Autowired
    StatusService statusService;
    private Logger log = Logger.getLogger(this.getClass());
    // The Java method will process HTTP GET requests

    @GET
    @Path("{code}")
    @Produces("application/xml")
    public Status getStatus(@PathParam("code") String code) {
        log.info("Hit getStatus");
        Status status = statusService.getByCode(code);
        log.info("Sending: \n\n" + status + "\n\n");
        return status;
    }


4. JPA impl class (Crete a interface too)
package com.persistent.service;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.persistent.entity.Status;
import com.persistent.service.StatusService;


@Service("statusService")
public class StatusServiceJpa implements StatusService {
    private Logger log = Logger.getLogger(this.getClass());
    private EntityManager entityManager;

    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    /* (non-Javadoc)
     * @see com.persistent.service.jpa.StatusService#getById(int)
     */
    @Transactional(readOnly = true)
    public Status getByCode(String code) {
        return entityManager.find(Status.class, code);
    }
}



5. Persistence.xml definition in META-INF directory of war file
<persistence xmlns="http://java.sun.com/xml/ns/persistence"

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
        version="1.0">

    <persistence-unit name="status_persistence" transaction-type="RESOURCE_LOCAL">
        <class>com.persistent.entity.Status</class>
    </persistence-unit>

</persistence>


6. Spring application context file contents - goes into WEB-INF/classes

<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
            http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-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/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
            ">
    <!--  Scan for both Jersey Rest Annotations a -->
    <context:component-scan
        base-package="com.persistent.rest,com.persistent.service,com.persistence.entity" />
    <context:annotation-config />
   
    <tx:annotation-driven />
   
    <jee:jndi-lookup id="dataSource" jndi-name="jdbc/BPPSDataSource" expected-type="javax.sql.DataSource"/>
   
    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
        p:dataSource-ref="dataSource" p:jpaVendorAdapter-ref="jpaAdapter">
        <property name="persistenceUnitName" value="status_persistence" />
        <property name="jpaProperties">
            <value>
                  hibernate.query.factory_class=org.hibernate.hql.classic.ClassicQueryTranslatorFactory
                hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect
                hibernate.connection.driver_class=oracle.jdbc.driver.OracleDriver
                  hibernate.show_sql=true
                hibernate.default_schema=BFPS
            </value>
        </property>
    </bean>
   
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
        p:entityManagerFactory-ref="entityManagerFactory" />
   
    <bean id="jpaAdapter"
        class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
        p:database="ORACLE" p:showSql="true" />
</beans>



7. web.xml definition
<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>Jersey Spring Web Application</servlet-name>
        <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey Spring Web Application</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
</web-app>



8. Maven pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.persistent</groupId>
    <artifactId>FFWD_NO_EJB</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>FFWD_NO_EJB</name>
    <repositories>
        <repository>
            <id>maven2-repository.dev.java.net</id>
            <name>Java.net Maven 2 Repository</name>
            <url>http://download.java.net/maven/2/</url>
            <!-- <layout>default</layout> -->
        </repository>
        <repository>
            <id>maven-repository.dev.java.net</id>
            <name>Java.net Maven 1 Repository (legacy)</name>
            <url>http://download.java.net/maven/1</url>
            <layout>legacy</layout>
        </repository>
    </repositories>
    <build>
        <finalName>FFWD_NO_EJB</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <inherited>true</inherited>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>maven-jetty-plugin</artifactId>
                <version>6.1.10</version>
            </plugin>
        </plugins>
    </build>
    <properties>
        <spring.version>2.5.5</spring.version>
        <hibernate.version>3.3.2.GA</hibernate.version>
        <commons-dbcp.version>1.2.2</commons-dbcp.version>
        <commons-logging.version>1.0.4</commons-logging.version>
        <jersey-version>1.0.2</jersey-version>
        <log4j.version>1.2.13</log4j.version>
    </properties>
    <dependencies>
        <!-- Adding in JPA With It's Requirements -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>${commons-logging.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring</artifactId>
            <version>${spring.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>persistence-api</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>${commons-dbcp.version}</version>
            <scope>runtime</scope>
        </dependency>
        <!--Explicitly add -->
        <!-- change cglib-nodep Farrukh Najmi From net.java.dev.jersey.users Dec.
            10, 2007 -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib-nodep</artifactId>
            <version>2.1_3</version>
        </dependency>
        <dependency>
            <groupId>geronimo-spec</groupId>
            <artifactId>geronimo-spec-jta</artifactId>
            <version>1.0.1B-rc4</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
           
            <!-- <artifactId>hibernate</artifactId> <version>3.2.5.ga</version> Explicitly
                remove: See: http://blog.interface21.com/main/2007/06/11/asm-version-incompatibilities-using-spring-autowired-with-hibernate/ -->
            <exclusions>
           
                <exclusion>
                    <groupId>javax.transaction</groupId>
                    <artifactId>jta</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>asm</groupId>
                    <artifactId>asm</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>asm</groupId>
                    <artifactId>asm-attrs</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>cglib</groupId>
                    <artifactId>cglib</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- JPA Additions end. -->
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>${jersey-version}</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey.contribs</groupId>
            <artifactId>jersey-spring</artifactId>
            <version>${jersey-version}</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
    </dependencies>
</project>



9. Access REST url at http://localhost:7001/FFWD/rest/status/S

Spring WS JAXB Web Sevice Client

1. See the WSDL and schema in my previous post here
2. Define beans in applicationContext.xml

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

<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory">
<property name="soapVersion">
<util:constant static-field="org.springframework.ws.soap.SoapVersion.SOAP_11" />
</property>
</bean>

<bean id="XYZOrderServiceMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPath" value="com.abc.XYZ.integration.test.jaxb" />
</bean>

<bean id="XYZOrderServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory" />
<property name="marshaller" ref="XYZOrderServiceMarshaller"></property>
<property name="unmarshaller" ref="XYZOrderServiceMarshaller"></property>
<property name="messageSender">
<bean
class="org.springframework.ws.transport.http.CommonsHttpMessageSender">
</bean>
</property>
<property name="defaultUri"
value="http://localhost:7001/XYZService/ws/XYZWebService.wsdl" />
</bean>

<bean id="XYZOrderServiceClient" class="com.abc.XYZ.integration.test.XYZOrderServiceClient">
<constructor-arg ref="XYZOrderServiceTemplate"></constructor-arg>
</bean>
</beans>

3. JUnit test case to invoke web service client

package com.abc.XYZ.integration.test;

import static org.junit.Assert.assertNotNull;

import org.junit.BeforeClass;
import org.junit.Test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class XYZServiceClientTest {

private static ClassPathXmlApplicationContext context = null;

@BeforeClass
public static void setUpBeforeClass() throws Exception {
context = new ClassPathXmlApplicationContext("/applicationContext.xml");
}

@Test
public void testPlaceOrder() {
XYZOrderServiceClient client = (XYZOrderServiceClient) context
.getBean("XYZOrderServiceClient");
String orderRef = client.placeOrder("offerId1");

assertNotNull(orderRef);
}
}

4. Service Client

package com.abc.XYZ.integration.test;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.ws.client.core.WebServiceTemplate;

import com.abc.XYZ.integration.test.jaxb.ObjectFactory;
import com.abc.XYZ.integration.test.jaxb.SendOrderRequest;
import com.abc.XYZ.integration.test.jaxb.SendOrderResponse;

public class XYZOrderServiceClient {

private static final Log logger = LogFactory.getLog(XYZOrderServiceClient.class);
private static final ObjectFactory WS_CLIENT_FACTORY = new ObjectFactory();

private WebServiceTemplate webServiceTemplate;

public XYZOrderServiceClient(WebServiceTemplate webServiceTemplate) {
this.webServiceTemplate = webServiceTemplate;
}

public String placeOrder(String offerId) {
logger.debug("Preparing PlaceOrderRequest.....");
SendOrderRequest request = WS_CLIENT_FACTORY.createSendOrderRequest();
request.setHHId(offerId);

logger.debug("Invoking Web service Operation[PlaceOrder]....");
SendOrderResponse response = (SendOrderResponse) webServiceTemplate
.marshalSendAndReceive(request);
logger.debug("Order reference:" + response.getField1());
return response.getField1();
}
}

5. maven POM.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.abc.XYZ.integration</groupId>
<artifactId>XYZtest</artifactId>
<version>0.0.1-SNAPSHOT</version>

<dependencies>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<scope>compile</scope>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-core</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
</dependencies>

<build>
<finalName>XYZServiceTest</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>com.sun.tools.xjc.maven2</groupId>
<artifactId>maven-jaxb-plugin</artifactId>
<version>1.1.1</version>
<configuration>
<generatePackage>com.abc.XYZ.integration.test.jaxb</generatePackage>
<schemaDirectory>src\main\resources</schemaDirectory>
<generateDirectory>src\main\java</generateDirectory>
<removeOldOutput>true</removeOldOutput>
<includeSchemas>
<includeSchema>*.xsd</includeSchema>
</includeSchemas>
<includeBindings>
<includeBinding>*.xjb</includeBinding>
</includeBindings>
<strict>false</strict>
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>



Wednesday, March 13, 2013

Spring Hibernate Java Maven war example

1. Project structure

C:.
├───.settings
├───src
│   └───main
│       ├───java
│       │   └───com
│       │       └───xyz
│       │           └───persistence
│       ├───resources --> where Status.hbm.xml and web-application-config.xml are
│       └───webapp
│           ├───META-INF
│           └───WEB-INF
└───target

2.Status.java POJO code - This represents a row in the mapped table
public class Status implements Serializable {

    private static final long serialVersionUID = 1L;

    public Status() {
        super();
    }

    private String statusCode;

    private String statusDescr;

    private Integer severity;

    private Date createTimestamp;

    private String createUserId;

    private String updUserId;

    private Date updTimestamp;

3. StatusDAO.java interface code
public interface StatusDAO {
    void save(Status status);
    void update(Status status);
    void delete(Status status);
    Status findByStatusCode(String statusCode);
}

4. StatusDAOImpl.java code

import java.util.List;

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

public class StatusDAOImpl extends HibernateDaoSupport implements StatusDAO {

    public void save(Status status) {
        getHibernateTemplate().save( status );
    }

    public void update(Status status) {
        getHibernateTemplate().update(status);
        
    }

    public void delete(Status status) {
        getHibernateTemplate().delete(status);        
    }

    public Status findByStatusCode(String statusCode) {
        List list = getHibernateTemplate().find(
                "from Status where statusCode=?",statusCode
          );
    return (Status)list.get(0);
    }

}


5. TestDriver.java code for running CRUD test cases

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


public class TestDriver {
    
    private StatusDAO statusDAO;
    
    public static void main(String[] args) {
        TestDriver driver = new TestDriver();
        try {
            driver.create();
            driver.retrieve();
            driver.update();
            driver.delete();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public TestDriver() {
        super();        
        ApplicationContext appContext = 
            new ClassPathXmlApplicationContext("/web-application-config.xml");
        statusDAO = (StatusDAO)appContext.getBean("statusDAO");
    }

    public void create() throws Exception {    
        
        Status status = createStatus();
        
        // create a new status in db
        createStatus(status);

        // retrieve a status from db
        Status retrievedStatus = statusDAO.findByStatusCode("RR");

        // delete a status
        deleteStatus(retrievedStatus);
    }

    public void retrieve() throws Exception {        
        create();
    }

    public void update() throws Exception {    
        Status status = createStatus();

        // create a new status in db
        createStatus(status);

        // retrieve a status
        Status retrievedStatus = statusDAO.findByStatusCode("RR");

        // update a status
        updateStatus();    

        // delete a status
        deleteStatus(retrievedStatus);
    }

    public void delete() throws Exception {        
        Status status = createStatus();

        createStatus(status);

        // retrieve a status
        Status retrievedStatus = statusDAO.findByStatusCode("RR");

        // update a status
        updateStatus();

        // delete a status
        deleteStatus(retrievedStatus);
    }

    private Status createStatus() {
        Status status = new Status();

        status.setStatusCode("RR");
        status.setCreateTimestamp(new Date());
        status.setCreateUserId("sssss");
        status.setSeverity(new Integer(22));
        status.setStatusDescr("testing-sss");
        status.setUpdTimestamp(new Date());
        status.setUpdUserId("sssss");
        return status;
    }

    private void createStatus(Status status) {
        statusDAO.save(status);
    }

    private void updateStatus() {
        Status retrievedStatus = statusDAO.findByStatusCode("RR");
        retrievedStatus.setStatusDescr("updated description");
        statusDAO.update(retrievedStatus);
    }

    private void deleteStatus(Status retrievedStatus) {
        statusDAO.delete(retrievedStatus);
    }

6. Status.hbm.xml file
<?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 package="com.xyz.persistence">
    <class name="Status" table="AUTH_STAT" mutable="false">
        <id name="statusCode" column="AUTH_STAT_CD" type="string"/>

        <property name="statusDescr" column="AUTH_STAT_DSC" type="string"/>
        <property name="severity" column="AUTH_SEREVITY_ID" type="integer"/>
        <property name="createTimestamp" column="CREATE_TS" type="timestamp"/>
        <property name="createUserId" column="CREATE_USER_ID" type="string"/>
        <property name="updUserId" column="UPD_USER_ID" type="string"/>
        <property name="updTimestamp" column="UPD_TS" type="timestamp"/>
    </class>
</hibernate-mapping>

7. Spring bean configuration file - web-application-config.xml
<?xml version="1.0" encoding="UTF-8"?>

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

    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
        <property name="url"
            value="jdbc:oracle:thin:@dbhost:20009:sid" />
        <property name="username" value="ddd" />
        <property name="password" value="ddd" />
    </bean>

    <!-- Hibernate session factory -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

        <property name="dataSource">
            <ref bean="dataSource" />
        </property>

        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.default_schema">SchemaName</prop>
            </props>
        </property>

        <property name="mappingResources">
            <list>
                <value>/Status.hbm.xml</value>
            </list>
        </property>

    </bean>

    <!-- Status Data Access Object -->
    <bean id="statusDAO" class="com.xyz.persistence.StatusDAOImpl">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>
</beans>


8. index.jsp code to call test driver
<?xml version="1.0" encoding="UTF-8" ?>

<%@ page import="com.xyz.persistence.TestDriver"%>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Hibernate + Oracle 11g DB CRUD test page</title>
</head>

<body>
    <%
        try {                
            TestDriver driver = new TestDriver();
            driver.create();
            out.println("Create Status succeeded");
            out.println("<br>");
            
            driver.retrieve();
            out.println("Retrieve Status succeeded");
            out.println("<br>");
            
            driver.update();
            out.println("Update Status succeeded");
            out.println("<br>");
            
            driver.delete();
            out.println("Delete Status succeeded");
            out.println("<br>");
            
            out.println("All CRUD operations succeeded");
        } catch (Exception e) {
            out.println("An exception occurred: " + e.getMessage());
        }
    %>
</body>

</html>


9. maven po.xml dependencies
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.6.1</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>3.3.2.GA</version>
        </dependency>

        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.12.1.GA</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>3.1.0.RELEASE</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>3.1.0.RELEASE</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>3.1.0.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.0</version>
            <scope>test</scope>
        </dependency>

Thursday, February 28, 2013

Spring-WS JAXB Java Webservice tutorial

This post shows how to create webservices using spring-ws. It took me a while to resolve numerous simple issues but I finally figured out how all this works.

I used "contract-first" approach by creating schema and wsdl first. Then, I created a Eclipse maven war type project, updated it with all required dependencies. One can take the reverse approach by exposing an EndPoint java class as a webservice and let Spring-ws publish wsdl dynamically.

I added a goal to generate Java code from schema that represents the payload of the webservice operations. 

I created a Java EndPoint class that will serve webservice requests.

Lastly, I created the spring webservices context file that defines all the webservice beans and marshaller/unmarshaller.

1. Define dispatcher servlet for Spring web services in  web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/web-application-config.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
<servlet-name>xyz-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
</servlet>

<servlet-mapping>
<servlet-name>xyz-ws</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>

2. Create spring-ws context xml file to define web service beans
<?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:sws="http://www.springframework.org/schema/web-services"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context.xsd
  http://www.springframework.org/schema/web-services
  http://www.springframework.org/schema/web-services/web-services-2.0.xsd">

  <sws:annotation-driven />

<context:component-scan base-package="com.xyz.abc.integration"
annotation-config="true" />

<bean id="XYZWebService"
class="org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition">
<constructor-arg value="classpath:/XYZWebService.wsdl"/>
</bean>

<bean id="XYZSchema" class="org.springframework.xml.xsd.SimpleXsdSchema">
<property name="xsd" value="classpath:/XYZSchema.xsd" />
</bean>

if you wanted Spring to generate wsdl automatically, comment out previous two lines and use this
<sws:dynamic-wsdl id="XYZWebService" portTypeName="XYZWebServicePort" locationUri="/xyzWebService/" targetNamespace="http://www.abc.com/XYZWebService/"> <sws:xsd location="classpath:/XYZSchema.xsd" /> </sws:dynamic-wsdl>

<bean id="marshallingPayloadMethodProcessor"
class="org.springframework.ws.server.endpoint.adapter.method.MarshallingPayloadMethodProcessor">
<constructor-arg ref="marshaller" />
</bean>

<bean id="defaultMethodEndpointAdapter"
class="org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter">
<property name="methodArgumentResolvers">
<list>
<ref bean="marshallingPayloadMethodProcessor" />
</list>
</property>
<property name="methodReturnValueHandlers">
<list>
<ref bean="marshallingPayloadMethodProcessor" />
</list>
</property>
</bean>

<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPath" value="com.xyz.abc.integration.jaxb" />
</bean>

<bean id="exceptionResolver"
class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">
<property name="defaultFault" value="SERVER" />
<property name="exceptionMappings">
<props>
<prop key="org.springframework.oxm.ValidationFailureException">CLIENT,Invalid</prop>
<prop key="javax.xml.bind.JAXBException">CLIENT,Invalid Request - Parser failed</prop>
</props>
</property>
</bean>

<bean id="xyzEndpoint" class="com.xyz.abc.integration.XYZEndpoint" scope="request">
<property name="someBusinessService" ref="someBusinessService"/>
</bean>

3. Create application context file to define other beans
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:annotation-config/>

<bean id="someBusinessService" class="com.xyz.abc.integration.SomeBusinessServiceImpl" scope="request"/>

</beans>

4. Create xsd schemas for webservice input/output
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.xyz.com/schemas/abc"
elementFormDefault="qualified">

<xsd:element name="SendOrderRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Field11" type="xsd:string" maxOccurs="1" minOccurs="0"/>
<xsd:element name="Filed22" type="xsd:string" maxOccurs="1" minOccurs="0" />
<xsd:element name="Field33" type="xsd:string" maxOccurs="1" minOccurs="0" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>

<xsd:element name="SendOrderResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Field1" type="xsd:string" maxOccurs="1" minOccurs="0" />
<xsd:element name="Field2" type="xsd:string" maxOccurs="1" minOccurs="0" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>

</xsd:schema>

5. Create WSDL for service

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.abc.com/XYZWebService"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:rew="http://www.abc.com/schemas/XYZ"
name="XYZWebService" targetNamespace="http://www.abc.com/XYZWebService/">

<wsdl:types>
<xsd:schema targetNamespace="http://www.abc.com/XYZWebService/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="http://www.abc.com/schemas/XYZ"
schemaLocation="XYZSchema.xsd" />
</xsd:schema>
</wsdl:types>
<wsdl:message name="sendOrderRequest">
<wsdl:part element="rew:SendOrderRequest" name="sendOrderRequest" />
</wsdl:message>
<wsdl:message name="sendOrderResponse">
<wsdl:part element="rew:SendOrderResponse" name="sendOrderResponse" />
</wsdl:message>

<wsdl:portType name="XYZWebService">
<wsdl:operation name="SendOrder">
<wsdl:input message="tns:sendOrderRequest" name="SendOrderRequest" />
<wsdl:output message="tns:sendOrderResponse" name="SendOrderResponse" />
</wsdl:operation>
</wsdl:portType>

<!-- Do we need to define soapAction -->
<wsdl:binding name="XYZWebServiceSOAP" type="tns:XYZWebService">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http" />

<wsdl:operation name="SendOrder">
<soap:operation soapAction="" />
<wsdl:input name="SendOrderRequest">
<soap:body use="literal" />
</wsdl:input>
<wsdl:output name="SendOrderResponse">
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="XYZWebService">
<wsdl:port binding="tns:XYZWebServiceSOAP" name="XYZWebServiceSOAP">
<soap:address location="http://localhost:7001/XYZService/ws" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>


6. Create Endpoint java class
@Endpoint
public class XYZEndpoint {

private static final Logger LOG = Logger.getLogger(XYZEndpoint.class);

private static final String NAMESPACE_URI = "http://www.xyz.com/schemas/xyz";


private SomeBusinessService someBusinessService;

public SomeBusinessService getSomeBusinessService() {
return this.someBusinessService;
}

public void setSomeBusinessService(SomeBusinessService someBusinessService) {
this.someBusinessService = someBusinessService;
}

@PayloadRoot(localPart = "SendOrderRequest", namespace = NAMESPACE_URI)
@ResponsePayload
public SendOrderResponse sendOrder(@RequestPayload SendOrderRequest request, SoapHeader header)
{
LOG.info("in sendOrder.....");
com.xyz.abc.integration.jaxb.ObjectFactory of = new com.xyz.abc.integration.jaxb.ObjectFactory();
SendOrderResponse resp = of.createSendOrderResponse();

resp.setField1(request.getField11());
return resp;
}

7. maven pom
<dependencies>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<scope>compile</scope>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-core</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
</dependencies>
<build>
<finalName>XYZService</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>com.sun.tools.xjc.maven2</groupId>
<artifactId>maven-jaxb-plugin</artifactId>
<version>1.1.1</version>
<configuration>
<generatePackage>com.xyz.abc.integration.jaxb</generatePackage>
<schemaDirectory>src\main\resources</schemaDirectory>
<generateDirectory>src\main\java</generateDirectory>
<removeOldOutput>true</removeOldOutput>
<includeSchemas>
<includeSchema>*.xsd</includeSchema>
</includeSchemas>
<includeBindings>
<includeBinding>*.xjb</includeBinding>
</includeBindings>
<strict>false</strict>
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

8. WSDL and XSD location

http://localhost:7001/XYZService/XYZWebService.wsdl
http://localhost:7001/XYZService/XYZSchema.xsd

9. SOAP UI 
http://localhost:7001/XYZService