WebSphere eXtreme Scale Programming Guide > Integrate with Spring framework



Native transactions


Spring is a popular framework for developing Java™ applications. WebSphere eXtreme Scale provides support to allow Spring to manage eXtreme Scale transactions and configure eXtreme Scale clients and servers.


Native transactions with WebSphere eXtreme Scale

Spring provides container-managed transactions along the style of a Java Platform, Enterprise Edition application server but has the advantage that Springs mechanism can have different implementations plugged in. This topic describes an eXtreme Scale Platform Transaction manager that can be used with Spring. This allows programmers to annotate their POJOs (plain old Java objects) and then have Spring automatically acquire Sessions from eXtreme Scale and begin, commit, rollback, suspend, and resume eXtreme Scale transactions. Spring transactions are described more fully in Chapter 10 of the official Spring User Guide. The following explains how to create an eXtreme Scale transaction manager and use it with annotated POJOs. It also explains how to use this approach with client or local eXtreme Scale as well as a collocated Data Grid style application.


Create a transaction manager

eXtreme Scale provides an implementation of a Spring PlatformTransactionManager. This manager can provide managed eXtreme Scale sessions to POJOs managed by Spring. Through the use of annotations, Spring manages those sessions for the POJOs in terms of transaction life cycle. The following XML snippet shows how to create a transaction Manager:

<aop:aspectj-autoproxy/>
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <bean id="ObjectGridManager"
                class="com.ibm.websphere.objectgrid.ObjectGridManagerFactory"
                factory-method="getObjectGridManager"/>

    <bean id="ObjectGrid"
                factory-bean="ObjectGridManager"
                factory-method="createObjectGrid"/>

    <bean id="transactionManager"
                class="com.ibm.websphere.objectgrid.spring.ObjectGridSpringFactory"
                factory-method="getLocalPlatformTransactionManager"/>
    </bean>

    <bean id="Service" class="com.ibm.websphere.objectgrid.spring.test.TestService">
        <property name="txManager" ref+"transactionManager"/>
    </bean>

This shows the transactionManager bean being declared and wired in to the Service bean that will use Spring transactions. We will demonstrate this using annotations and this is the reason for the tx:annotation clause at the beginning.


Obtaining an ObjectGrid Session for the current Spring transaction

A POJO that has methods managed by Spring can now obtain the ObjectGrid session for the current transaction using

Session s = txManager.getSession();

This returns the session for the POJO to use. Beans participating in the same transaction will receive the same session when they call this method. Spring will automatically handle begin for the Session and also automatically invoke commit or rollback when necessary. You can obtain an ObjectGrid EntityManager also by simply calling getEntityManager from the Session object.


A sample POJO using annotations

Here is a POJO that uses annotations to declare its transactional intentions to Spring. You can see the class has a class level annotation indicating all methods by default should use REQUIRED transaction semantics. The class implements an interface with a method for all methods on the class. This is necessary for Spring AOP to work when it cannot do bytecode weaving. The class has an instance variable txManager that we wire to the ObjectGrid transaction manager using the Spring xml file. Each method simply calls the txManager.getSession method to obtain the Session to use for the method.The queryNewTx method is annotated to indicate a REQUIRES_NEW semantic. This means any existing transaction will be suspended and a new independent transaction created for that method.

@Transactional(propagation=Propagation.REQUIRED)
public class TestService implements ITestService 
{
    SpringLocalTxManager txManager;
    
    public TestService()
    {
        
    }
    
    public void initialize()
        throws ObjectGridException
    {
        Session s = txManager.getSession();
        ObjectMap m = s.getMap("TEST");
        m.insert("Hello", "Billy");
    }
    
    public void update(String updatedValue)
        throws ObjectGridException
    {
        Session s = txManager.getSession();
        System.out.println("Update using " + s);
        ObjectMap m = s.getMap("TEST");
        String v = (String)m.get("Hello");
        m.update("Hello", updatedValue);
    }
    
    public String query()
        throws ObjectGridException
    {
        Session s = txManager.getSession();
        System.out.println("Query using " + s);
        ObjectMap m = s.getMap("TEST");
        return (String)m.get("Hello");
    }

    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public String queryNewTx()
        throws ObjectGridException
    {
        Session s = txManager.getSession();
        System.out.println("QueryTX using " + s);
        ObjectMap m = s.getMap("TEST");
        return (String)m.get("Hello");
    }

    public void testRequiresNew(ITestService bean)
        throws ObjectGridException
    {
        update("1");
        String txValue = bean.query();
        if(!txValue.equals("1"))
        {
            System.out.println("Requires didnt work");
            throw new IllegalStateException("requires didn't work");
        }
        String committedValue = bean.queryNewTx();
        if(committedValue.equals("1"))
        {
            System.out.println("Requires new didnt work");
            throw new IllegalStateException("requires new didn't work");
        }
    }

    public SpringLocalTxManager getTxManager() {
        return txManager;
    }

    public void setTxManager(SpringLocalTxManager txManager) {
        this.txManager = txManager;
    }
}


Set the ObjectGrid instance for a thread

A single Java Virtual Machine (JVM) can host many ObjectGrid instances. Each primary shard placed in a JVM has its own ObjectGrid instance. A JVM acting as a client to a remote ObjectGrid uses an ObjectGrid instance returned from the connect method's ClientClusterContext to interact with that Grid. Before invoking a method on a POJO using Spring transactions for ObjectGrid, the thread must be primed with the ObjectGrid instance to use. The TransactionManager instance has a method allowing a specific ObjectGrid instance to be specified. Once specified then any subsequent txManager.getSession calls will returns Sessions for that ObjectGrid instance.


Simple bootstrap for testing

The following example shows a sample main for exercising this capability:

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]
            {"applicationContext.xml"});
    SpringLocalTxManager txManager = (SpringLocalTxManager)ctx.getBean("transactionManager");
    txManager.setObjectGridForThread(og);
        
    ITestService s = (ITestService)ctx.getBean("Service");
    s.initialize();
    assertEquals(s.query(), "Billy");
    s.update("Bobby");
    assertEquals(s.query(), "Bobby");
    System.out.println("Requires new test");
    s.testRequiresNew(s);
    assertEquals(s.query(), "1");

Here we use a Spring ApplicationContext. The ApplicationContext is used to obtain a reference to the txManager and specify an ObjectGrid to use on this thread. The code then obtains a reference to the service and invokes methods on it. Each method call at this level causes Spring to create a Session and do begin/commit calls around the method call. Any exceptions will cause a rollback.


New eXtreme Scale interfaces

This introduces a single new interface, SpringLocalTxManager. This interface is implemented by the ObjectGrid Platform Transaction Manager and has all public interfaces. The methods on this interface are for selecting the ObjectGrid instance to use on a thread and obtaining a Session for the thread. Any POJOs using ObjectGrid local transactions should be injected with a reference to this manager instance and only a single instance need be created, that is, its scope should be singleton.This instance is created using a static method on ObjectGridSpringFactory. getLocalPlatformTransactionManager().


eXtreme Scale for JTA and global transactions

eXtreme Scale does not support JTA or 2 phase commit for various reasons mainly to do with scalability. Thus, except at a last single-phase participant, ObjectGrid does not interact in XA or JTA type global transactions. This platform manager is intended to make using local ObjectGrid transactions as easy as possible for Spring developers.


Spring managed extension beans

ObjectGrid includes an approach to declare POJOs to use as extension points in the objectgrid.xml file. ObjectGrid provides a way to name the beans and then specify the class name. ObjectGrid normally creates instances of the specified class and uses those instances as the plug-in. ObjectGrid can now delegate to Spring to act as the bean factory for obtaining instances of these plug-in objects. If an application uses Spring then typically such POJOs have a requirement to be wired in to the rest of the application.

ObjectGrid has been modified to allow an application to register a Spring Bean Factory instance to use for a specific named ObjectGrid. The application should create an instance of BeanFactory or a Spring application context and then register it with ObjectGrid using the following static method:

void registerSpringBeanFactoryAdapter(String objectGridName, Object springBeanFactory)

This method specifies that if ObjectGrid finds an extension bean (such as an ObjectTransformer, Loader, TransactionCallback, and so on) whose className begins with the prefix {spring} then use the remainder of the name as a Spring Bean name and obtain the bean instance using the Spring Bean Factory. ObjectGrid can also create a Spring bean factory from a default spring xml configuration file. If no bean factory was registered for a given ObjectGrid then ObjectGrid tries to find an xml file called 'ObjectGridName'_spring.xml. For example, if your grid is called GRID then the xml file is called '/GRID_spring.xml' and should be in the class path in the root package. If this file is found then ObjectGrid constructs an ApplicationContext using that file and constructs beans from that bean factory. As example class name would be:

"{spring}MyLoaderBean"

This would cause ObjectGrid to ask Spring for a bean named "MyLoaderBean". This approach can be used to specify Spring managed POJOs for any extension point in ObjectGrid so long as the bean factory has been registered up front. The ObjectGrid spring extensions are in the ogspring.jar file. This jar file must be on the class path for spring support to work due. If a JavaEE application running in an XD augmented ND then the application should place the spring.jar file and its associated files in the EAR modules. The ogspring.jar must also be placed in the same location.


Spring Webflow

Spring Webflow stores its session state in the HTTP Session by default. If a web application is configured to use ObjectGrid for session management then ObjectGrid will be used automatically by Spring to store this state and it will be made fault tolerant in the same manner as the session.



Parent topic

Integrate with Spring framework


+

Search Tips   |   Advanced Search