Tag: Spring

Monitoring Spring in WebLogic

The Spring console extension is based on RuntimeMBeans registered using the WebLogic Server infrastructure; therefore, it provides a cluster view of the Spring applications and more management functionality for Spring Beans. It creates a Spring tab parallel to the Web or EJB applications, and it allows user to view the configuration information of the Spring bean on the WebLogic Administration Console.

To use the Spring console extension, we must turn on support for Spring beans and enable the Spring console extension. To enable the Spring console extension in the Administration Console, perform the following steps:

  • In the banner toolbar region at the top of the Console, click Preferences.
  • On the Preferences page, click Extensions.
  • Select the check box next to spring-console, then click Enable.
  • Restart the server, the change to take effect.

Next, deploy the weblogic-spring.jar (located in the ${WL_HOME}/server/lib directory) as a JavaEE optional package. To deploy the optional package using the Administration Console the steps that are described here can be used.

To be able to use the Spring console extension, we must have a Web component as part of our application. We take the application introduced in the post Spring and Hibernate4 as the basis and extend this application with a Web module. Edit the web.xml deployment descriptor such that a Spring Context is created

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-config.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

To generate runtime MBeans for the application, the WeblogicSpringApplicationListener from weblogic-spring.jar must be added as a listener to the root Spring context:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
    <bean class="weblogic.spring.monitoring.WeblogicSpringApplicationListener"/>
    <bean id="company" class="model.logic.CompanyBean">
        <property name="sessionFactory" ref="sessionfactory"/>
        <property name="jmsTemplate" ref="jmstemplate"/>
    </bean>
    <!-- Hibernate Config -->
    <bean id="sessionfactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="datasource"/>
        <property name="jtaTransactionManager" ref="transactionManager"/>
        <property name="mappingResources">
            <list>
                <value>model/entities/person.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.current_session_context_class">${hibernate.current_session_context_class}</prop>
                <prop key="hibernate.listeners.envers.autoRegister">${hibernate.listeners.envers.autoRegister}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
            </props>
        </property>
    </bean>
    <!-- Transaction Config -->
    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
    <tx:annotation-driven transaction-manager="transactionManager"/>
    <!-- Resource Config -->
    <jee:jndi-lookup id="datasource" jndi-name="jdbc/exampleDS" resource-ref="false"/>
    <jee:jndi-lookup id="connectionfactory" jndi-name="jms/ConnectionFactory" resource-ref="false"/>
    <jee:jndi-lookup id="destination" jndi-name="jms/CompanyQueue" resource-ref="false"/>
    <!-- JMS Config -->
    <bean id="jmstemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionfactory"/>
        <property name="defaultDestination" ref="destination"/>
    </bean>
    <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionfactory"/>
        <property name="destination" ref="destination"/>
        <property name="transactionManager" ref="transactionManager"/>
        <property name="messageListener" ref="companymdp"/>
    </bean>
    <bean id="companymdp" class="model.logic.CompanyMDP"/>
    <!-- Extra -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:spring.properties</value>
            </list>
        </property>
    </bean>
</beans>

Finally, add (or change) the MANIFEST.MF (located in the META-INF directory) and make sure the following lines are included:

Extension-List: WeblogicSpring
WeblogicSpring-Extension-Name: weblogic-spring
WeblogicSpring-Specification-Version: 12.1.1.0
WeblogicSpring-Implementation-Version: 12.1.1.0

For the version and extension name to use, check the MANIFEST.MF included in the weblogic-spring.jar, in our case it contained the following:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Created-By: R28.2.0-79-146777-1.6.0_29-20111005-1808-windows-ia32 (Oracle Corporation)
Extension-Name: weblogic-spring
Implementation-Vendor: BEA Systems
Implementation-Title: WebLogic Server 12.1  Wed Dec 7 08:40:57 PST 2011 1445491
Implementation-Version: 12.1.1.0
Specification-Vendor: BEA Systems
Specification-Title: WebLogic Server
Specification-Version: 12.1.1.0

Deploy the application. By clicking on the deployment Spring Framework, Configuration tab, we obtain the following information

Issue some requests to the testservlet and click Spring Framework, Monitoring tab. Here, we can obtain the following information

References

[1] Spring Console Extension in WebLogic Server.
[2] Spring 2.5.x and WebLogic Server 10.3 Integration.


Spring and Hibernate4

In this post we put Spring and Hibernate 4 together. We start out by creating a Java client to see what is needed to make things work. Next, we create a Web application (by adding a servlet) and deploy the application to JBoss AS7 (and use the native Hibernate API). Here, we show what needs to be done in order to make Spring and the native Hibernate API work together on the JBoss Application Server, i.e., we create an extra module (org.springframework) and make sure this is loaded by the deployed Web module. Finally, we show how to include messaging as well. More information on how the JBoss environment is set-up can be found in the post Building a Coherence Cluster with Multiple Application Servers. We also show how the environment can be migrated from JBoss to WebLogic (or vice versa). More information about the WebLogic environment can be found in the post Deploy WebLogic12c to Multiple Machines.

Client

Let us start by creating a Java client, just to get a feeling of what needs to be done and not have the complexity of a Java EE Server (such as, for example, JBoss AS7) along with it. To this end we can use the following Spring configuration

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
    <bean id="company" class="model.logic.CompanyBean">
        <property name="sessionFactory" ref="sessionfactory"/>
    </bean>
    <bean id="sessionfactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="datasource"/>
        <!--property name="jtaTransactionManager" ref="transactionManager"/-->
        <property name="mappingResources">
            <list>
                <value>model/entities/person.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <!--prop key="hibernate.current_session_context_class">${hibernate.current_session_context_class}</prop-->
                <prop key="hibernate.listeners.envers.autoRegister">${hibernate.listeners.envers.autoRegister}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
            </props>
        </property>
    </bean>
    <!--jee:jndi-lookup id="datasource" jndi-name="java:/jdbc/OracleDS" resource-ref="false"/-->
    <bean id="datasource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
        <property name="driverType" value="${jdbc.driverClassName}"/>
        <property name="URL" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:spring.properties</value>
            </list>
        </property>
    </bean>
    <!--bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/-->
    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionfactory"/>
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

Note that we did not set the hibernate.current_session_context_class property. We should never use that property when combining Hibernate with Spring as it destroys proper session and transaction management when using the HibernateTransactionManager. On the other hand, when on a Java EE Server and using the JtaTransactionManager, set the property to the value thread. Another thing to note is that the EnversIntegrator is always detected by default while initializing the ServiceRegistry using the Native Hibernate API causing a MappingException even when Envers is not used when deployed on JBoss AS7. That is why we have set the value of the hibernate.listeners.envers.autoRegister property to false.

The contents of the referred spring.properties look as follows

jdbc.driverClassName=oracle.jdbc.OracleDriver
jdbc.url=jdbc:oracle:thin:@192.168.1.60:1521:orcl11
jdbc.username=example
jdbc.password=example

hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
hibernate.current_session_context_class=thread
hibernate.listeners.envers.autoRegister=false
hibernate.show_sql=false
hibernate.format_sql=false

The CompanyBean class looks as follows

package model.logic;

import model.entities.Person;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public class CompanyBean implements Company {

    private SessionFactory sessionFactory;

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public void insertPerson(Person person) {
        Person temporaryPerson = findPerson(person.getSofinummer());
        if (temporaryPerson == null) {
            System.out.println("INSERT " + person);
            getCurrentSession().save(person);
        } else {
            updatePerson(person);
        }
    }

    public void removePerson(Integer sofinummer) {
        Person temporaryPerson = findPerson(sofinummer);
        if (temporaryPerson != null) {
            System.out.println("REMOVE " + temporaryPerson);
            getCurrentSession().delete(temporaryPerson);
        }
    }

    public void updatePerson(Person person) {
        System.out.println("UPDATE " + person);
        getCurrentSession().merge(person);
    }

    private Person findPerson(Integer sofinummer) {
        return (Person) getCurrentSession().get(Person.class, sofinummer);
    }

    private final Session getCurrentSession(){
      return getSessionFactory().getCurrentSession();
   }
}

To test the set-up, we can use something like

package model.test;

import model.entities.Person;
import model.logic.Company;
import model.utils.SpringUtilities;

import java.util.Random;

public class Test {

    private Random generator = new Random();

    public static void main(String[] args) {
        Test test = new Test();

        Company company = SpringUtilities.getCompany();

        for (int i = 0; i &lt; 100; i++) {
            Person person = test.createPerson();
            if (test.generator.nextDouble() &lt; 0.01) {
                company.removePerson(person.getSofinummer());
            } else {
                company.insertPerson(person);
            }
        }
    }

    private Person createPerson() {
        Person person = new Person();
        person.setNaam(Long.toString(Math.abs(generator.nextLong()), 36));
        person.setSofinummer(generator.nextInt(10000));
        return person;
    }
}

When the test is run something like the following output is observed

Aug 14, 2012 2:59:35 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@145d068: startup date [Tue Aug 14 14:59:35 CEST 2012]; root of context hierarchy
Aug 14, 2012 2:59:35 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring-config.xml]
Aug 14, 2012 2:59:36 PM org.springframework.core.io.support.PropertiesLoaderSupport loadProperties
INFO: Loading properties file from class path resource [spring.properties]
Aug 14, 2012 2:59:36 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1faba46: defining beans [company,sessionfactory,datasource,propertyConfigurer,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor]; root of factory hierarchy
Aug 14, 2012 2:59:36 PM org.hibernate.annotations.common.Version <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.1.Final}
Aug 14, 2012 2:59:36 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.1.2.Final}
Aug 14, 2012 2:59:36 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
Aug 14, 2012 2:59:36 PM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
Aug 14, 2012 2:59:36 PM org.hibernate.internal.util.xml.DTDEntityResolver resolveEntity
WARN: HHH000223: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/. Use namespace http://www.hibernate.org/dtd/ instead. Refer to Hibernate 3.6 Migration Guide!
Aug 14, 2012 2:59:36 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.Oracle10gDialect
Aug 14, 2012 2:59:36 PM org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
INFO: HHH000399: Using default transaction strategy (direct JDBC transactions)
Aug 14, 2012 2:59:36 PM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
Aug 14, 2012 2:59:36 PM org.hibernate.validator.internal.util.Version <clinit>
INFO: HV000001: Hibernate Validator 4.3.0.Final
Aug 14, 2012 2:59:36 PM org.springframework.orm.hibernate4.HibernateTransactionManager afterPropertiesSet
INFO: Using DataSource [oracle.jdbc.pool.OracleDataSource@161f39e] of Hibernate SessionFactory for HibernateTransactionManager
UPDATE 179arxyy6tshk 6176
INSERT 1sf4e5oz89uhi 2402
UPDATE t9pjpfnqxc4k 8413
UPDATE 1ckym7ttz46mf 5246
UPDATE 1u7litwyaigu4 1211
INSERT 74ra63w7aql6 2238
INSERT 5v48tzzk75qo 5902
INSERT mh5zpr30rjkd 2082
UPDATE 13xzu6r3g0ruz 5877
UPDATE 1jeqjhlfjwv81 9332
INSERT 19zb01tagisqq 6022
INSERT q5v1re6g6svp 3071
INSERT 12t5tsoyld5nl 9991
INSERT m7dhwiwvx7oi 9089
INSERT 1hz8k3rq1cngf 5596
UPDATE 14hhycu8lxban 4169
INSERT 4hh6749zjr67 2970
INSERT 143ofpk3kupmn 8769
UPDATE 16cfhq1shjzu7 8439
UPDATE scijv0dgh6m4 4234

Server

When we want to run the application on a Java EE Server, such as JBoss AS7, we can use the JtaTransactionManager instead of the HibernateTransactionManager. We also get a reference to a datasource by looking it up in JNDI, i.e.,

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
    <bean id="company" class="model.logic.CompanyBean">
        <property name="sessionFactory" ref="sessionfactory"/>
    </bean>
    <bean id="sessionfactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="datasource"/>
        <property name="jtaTransactionManager" ref="transactionManager"/>
        <property name="mappingResources">
            <list>
                <value>model/entities/person.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.current_session_context_class">${hibernate.current_session_context_class}</prop>
                <prop key="hibernate.listeners.envers.autoRegister">${hibernate.listeners.envers.autoRegister}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
            </props>
        </property>
    </bean>
    <jee:jndi-lookup id="datasource" jndi-name="java:/jdbc/OracleDS" resource-ref="false"/>
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:spring.properties</value>
            </list>
        </property>
    </bean>
    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

To test the configuration we can use the following servlet

package userinterface.servlets;

import model.entities.Person;
import model.logic.Company;
import model.utils.SpringUtilities;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Random;

@WebServlet(name = "TestServlet", urlPatterns = "/testservlet")
public class TestServlet extends HttpServlet {

    private Random generator = null;
    private Company company = null;

    @Override
    public void init() throws ServletException {
        generator = new Random();
        company = SpringUtilities.getCompany();
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Person person = createPerson();

        if (generator.nextDouble() &lt; 0.01) {
            company.removePerson(person.getSofinummer());
        } else {
            company.insertPerson(person);
        }
    }

    @Override
    public void destroy() {
        generator = null;
        company = null;
    }

    private Person createPerson() {
        Person person = new Person();
        person.setNaam(Long.toString(Math.abs(generator.nextLong()), 36));
        person.setSofinummer(generator.nextInt(10000));
        return person;
    }
}

One thing to note is that when we need to develop a servlet (by using an IDE) we have to make sure the right classes are on the classpath. Usually, when developing a Java EE application the javaee-api-6.0.jar would suffice. One thing to note is that if we were to run our Test class again we would run into the following: Caused by: java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/validation/Validation. To resolve this we need the full implementation of the bean-validator.jar on the classpath and make sure that it is loaded before the javaee-api-6.0.jar.

Before, we can deploy the application we have to make sure the Spring classes are picked up by the Web module. To this end, we create the following module on JBoss AS7. First, create a directory structure that includes the necessary jars and a module.xml file as follows

${JBOSS_HOME}/modules
	/org/springframework
		/main
			aopalliance-1.0.jar
			cglib-2.2.2.jar
			commons-logging-1.0.4.jar
			module.xml
			org.springframework.aop-3.1.2.RELEASE.jar
			org.springframework.asm-3.1.2.RELEASE.jar
			org.springframework.beans-3.1.2.RELEASE.jar
			org.springframework.context-3.1.2.RELEASE.jar
			org.springframework.core-3.1.2.RELEASE.jar
			org.springframework.expression-3.1.2.RELEASE.jar
			org.springframework.jdbc-3.1.2.RELEASE.jar
			org.springframework.jms-3.1.2.RELEASE.jar
			org.springframework.orm-3.1.2.RELEASE.jar
			org.springframework.transaction-3.1.2.RELEASE.jar
			org.springframework.web-3.1.2.RELEASE.jar

where module.xml has the following contents

<module xmlns="urn:jboss:module:1.1" name="org.springframework">
    <resources>
		<resource-root path="aopalliance-1.0.jar"/>
		<resource-root path="cglib-2.2.2.jar"/>
		<resource-root path="commons-logging-1.0.4.jar"/>
		<resource-root path="org.springframework.aop-3.1.2.RELEASE.jar"/>
		<resource-root path="org.springframework.asm-3.1.2.RELEASE.jar"/>
		<resource-root path="org.springframework.beans-3.1.2.RELEASE.jar"/>
		<resource-root path="org.springframework.context-3.1.2.RELEASE.jar"/>
		<resource-root path="org.springframework.core-3.1.2.RELEASE.jar"/>
		<resource-root path="org.springframework.expression-3.1.2.RELEASE.jar"/>
		<resource-root path="org.springframework.jdbc-3.1.2.RELEASE.jar"/>
		<resource-root path="org.springframework.jms-3.1.2.RELEASE.jar"/>
		<resource-root path="org.springframework.orm-3.1.2.RELEASE.jar"/>
		<resource-root path="org.springframework.transaction-3.1.2.RELEASE.jar"/>
		<resource-root path="org.springframework.web-3.1.2.RELEASE.jar"/>
    </resources>
    <dependencies>
        <module name="javax.api" export="true"/>
        <module name="org.apache.log4j" export="true"/>
        <module name="org.antlr" export="true"/>
        <module name="org.dom4j" export="true"/>
        <module name="org.hibernate" export="true"/>
        <module name="javax.persistence.api" export="true"/>
        <module name="org.javassist" export="true"/>
        <module name="org.jboss.logging" export="true"/>
        <module name="javax.transaction.api" export="true"/>
    </dependencies>
</module>

Note that we also have included a Hibernate dependency (as this is needed by Spring when using Hibernate with it). To make sure we have all the required files, we can check a Hibernate 4 distribution and look in the ${HIBERNATE_HOME}/lib/required directory. That is, we need the following jars:

antlr-2.7.7.jar (loaded by adding the module org.antlr)
dom4j-1.6.1.jar (loaded by adding the module org.dom4j)
hibernate-commons-annotations-4.0.1.Final.jar (loaded by adding the module org.hibernate)
hibernate-core-4.0.1.Final.jar (loaded by adding the module org.hibernate)
hibernate-jpa-2.0-api-1.0.1.Final.jar (loaded by adding the module javax.persistence.api)
javassist-3.15.0-GA.jar (loaded by adding the module org.javassist)
jboss-logging-3.1.0.GA.jar (loaded by adding the module org.jboss.logging)
jboss-transaction-api_1.1_spec-1.0.0.Final.jar (loaded by adding the module javax.transaction.api)

Another important module that Spring depends on is the javax.api, as Spring needs XML related classes, such as parsers. Note that JBoss AS7 does not make javax packages, that are present in rt.jar, available. To make this happen we need to include the javax.api module. One important thing to note is that the javax.api module does not include a reference to javax.xml.parsers. To this end, edit the module.xml (located in the ${JBOSS_HOME}/modules/javax/api/main directory) and make sure that it does, i.e.,

<module xmlns="urn:jboss:module:1.1" name="javax.api">
    <dependencies>
        <system export="true">
            <paths>
				...
				<!-- To resolve java.lang.ClassNotFoundException: javax.xml.parsers.ParserConfigurationException from [Module "org.springframework:main" from local module loader @2393385d (roots: /home/jboss/jboss-as-7.1.0.Final/modules)] we have to add -->
                <path name="javax/xml/parsers"/>
				...
				<!-- java.lang.ClassNotFoundException: org.xml.sax.EntityResolver from [Module "org.springframework:main" from local module loader @2393385d (roots: /home/jboss/jboss-as-7.1.0.Final/modules)] is the first ClassNotFoundException we run into if the javax.api module is not added as a dependency to the org.springframework module -->
                <path name="org/xml/sax"/>
                <path name="org/xml/sax/ext"/>
                <path name="org/xml/sax/helpers"/>
            </paths>
        </system>
    </dependencies>
</module>

With the modules in place, restart the servers to make sure the modules are loaded

[jboss@axis-into-ict ~]$ cd jboss-as-7.1.0.Final/bin/

[jboss@axis-into-ict bin]$ ./jboss-cli.sh
You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands.

[disconnected /] connect 192.168.1.150:9999

[domain@192.168.1.150:9999 /] /host=jboss/server-config=cluster-server1:restart
{
    "outcome" => "success",
    "result" => "STARTING"
}
[domain@192.168.1.150:9999 /] /host=jboss/server-config=cluster-server2:restart
{
    "outcome" => "success",
    "result" => "STARTING"
}

As we are dealing with a .war deployment, we have to add the jboss-deployment-structure.xml file to the WEB-INF directory, such that the org.springframework module can be accessed by the Web module. The contents of jboss-deployment-structure.xml look as follows

<jboss-deployment-structure>
    <deployment>
        <dependencies>
            <module name="org.springframework">
				<imports>
					<include path="META-INF**"/>
					<include path="org**"/>
				</imports>
			</module>
        </dependencies>
    </deployment>
</jboss-deployment-structure>

The imports element above is critical for the proper functioning of the Spring custom name-space capabilities. Applications that use custom name-spaces and wish to use a shared Spring module must use the JBoss deployment structure descriptors with the imports above. To deploy the application we can use

[domain@192.168.1.150:9999 /] deploy /home/jboss/jboss-as-7.1.0.Final/deploy/springhibernate/SpringHibernate.war --server-groups=cluster-group
[domain@192.168.1.150:9999 /] undeploy SpringHibernate.war --server-groups=cluster-group

which also shows how to undeploy it. The application can be reached at http://192.168.1.150:8888/SpringHibernate/testservlet. After doing a few requests the following is observed in the logging:

# LOGGING CLUSTER_SERVER1
12:52:50,289 INFO  [org.springframework.context.support.ClassPathXmlApplicationContext] (ajp--192.168.1.150-9080-3) Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@876e4b8: startup date [Tue Aug 14 12:52:50 CEST 2012]; root of context hierarchy
12:52:50,294 INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (ajp--192.168.1.150-9080-3) Loading XML bean definitions from class path resource [spring-config.xml]
12:52:50,345 INFO  [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer] (ajp--192.168.1.150-9080-3) Loading properties file from class path resource [spring.properties]
12:52:50,348 INFO  [org.springframework.beans.factory.support.DefaultListableBeanFactory] (ajp--192.168.1.150-9080-3) Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6ddb6b07: defining beans [company,sessionfactory,datasource,propertyConfigurer,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor]; root of factory hierarchy
12:52:50,366 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp--192.168.1.150-9080-3) Using JTA UserTransaction: org.jboss.tm.usertx.client.ServerVMClientUserTransaction@2cc821ef
12:52:50,367 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp--192.168.1.150-9080-3) Using JTA TransactionManager: com.arjuna.ats.jbossatx.jta.TransactionManagerDelegate@500b3f4c
12:52:50,368 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp--192.168.1.150-9080-3) Using JTA TransactionSynchronizationRegistry: com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple@26b58796
12:52:50,374 WARN  [org.hibernate.internal.util.xml.DTDEntityResolver] (ajp--192.168.1.150-9080-3) HHH000223: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/. Use namespace http://www.hibernate.org/dtd/ instead. Refer to Hibernate 3.6 Migration Guide!
12:52:50,425 INFO  [org.hibernate.dialect.Dialect] (ajp--192.168.1.150-9080-3) HHH000400: Using dialect: org.hibernate.dialect.Oracle10gDialect
12:52:50,428 INFO  [org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory] (ajp--192.168.1.150-9080-3) HHH000397: Using ASTQueryTranslatorFactory
12:52:50,605 INFO  [stdout] (ajp--192.168.1.150-9080-3) UPDATE meh9qfr1uqch 5938
13:03:16,102 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE wegp27iyxw0j 2846
13:03:16,648 INFO  [stdout] (ajp--192.168.1.150-9080-4) INSERT 1xddpcvtis10e 5966
13:03:16,754 INFO  [stdout] (ajp--192.168.1.150-9080-7) INSERT mhvagbqaxgsd 7337
13:03:16,792 INFO  [stdout] (ajp--192.168.1.150-9080-7) UPDATE 34fxu4haa4q5 9804
13:03:16,866 INFO  [stdout] (ajp--192.168.1.150-9080-3) UPDATE 5amkxlyuzyp8 8927
13:03:16,942 INFO  [stdout] (ajp--192.168.1.150-9080-3) UPDATE 11ykc13m0r10b 4393
13:03:17,611 INFO  [stdout] (ajp--192.168.1.150-9080-3) INSERT 1fkms210dthwr 488
13:03:18,198 INFO  [stdout] (ajp--192.168.1.150-9080-3) INSERT cfp1i5sy4bpt 3455
13:03:18,223 INFO  [stdout] (ajp--192.168.1.150-9080-7) UPDATE p9jqdlnpv5d8 1074
13:03:18,246 INFO  [stdout] (ajp--192.168.1.150-9080-4) INSERT fnu0r03mgas0 2027
13:03:18,263 INFO  [stdout] (ajp--192.168.1.150-9080-3) UPDATE dgh5ib56gze7 1215
13:03:18,296 INFO  [stdout] (ajp--192.168.1.150-9080-7) INSERT 1n4x67w9aufr 7767
13:03:18,297 INFO  [stdout] (ajp--192.168.1.150-9080-9) UPDATE 8xy8prwm00yy 8807
13:03:18,326 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE 1jkvwulhwqksx 6280
13:03:18,334 INFO  [stdout] (ajp--192.168.1.150-9080-8) INSERT 1lrmb4dyxurp2 5249
13:03:18,339 INFO  [stdout] (ajp--192.168.1.150-9080-3) UPDATE mo1vpdb5v0sm 5048
13:03:18,345 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE qb6e3wq3ok05 7163
13:03:18,357 INFO  [stdout] (ajp--192.168.1.150-9080-3) INSERT wlxcjpediiml 961
13:03:18,358 INFO  [stdout] (ajp--192.168.1.150-9080-2) INSERT fr6ji76ohzsi 842
13:03:18,365 INFO  [stdout] (ajp--192.168.1.150-9080-7) INSERT 1otburj6mb9er 7645
13:03:18,372 INFO  [stdout] (ajp--192.168.1.150-9080-9) INSERT 198eulbfrkd0b 6503
# LOGGING CLUSTER_SERVER2
13:03:16,786 INFO  [org.springframework.context.support.ClassPathXmlApplicationContext] (ajp--192.168.1.150-9081-2) Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@652130d1: startup date [Tue Aug 14 13:03:16 CEST 2012]; root of context hierarchy
13:03:16,830 INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (ajp--192.168.1.150-9081-2) Loading XML bean definitions from class path resource [spring-config.xml]
13:03:17,107 INFO  [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer] (ajp--192.168.1.150-9081-2) Loading properties file from class path resource [spring.properties]
13:03:17,127 INFO  [org.springframework.beans.factory.support.DefaultListableBeanFactory] (ajp--192.168.1.150-9081-2) Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@5c594008: defining beans [company,sessionfactory,datasource,propertyConfigurer,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor]; root of factory hierarchy
13:03:17,191 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp--192.168.1.150-9081-2) Using JTA UserTransaction: org.jboss.tm.usertx.client.ServerVMClientUserTransaction@6ebfc8d0
13:03:17,192 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp--192.168.1.150-9081-2) Using JTA TransactionManager: com.arjuna.ats.jbossatx.jta.TransactionManagerDelegate@3839029b
13:03:17,193 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp--192.168.1.150-9081-2) Using JTA TransactionSynchronizationRegistry: com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple@33ec79b6
13:03:17,286 INFO  [org.hibernate.annotations.common.Version] (ajp--192.168.1.150-9081-2) HCANN000001: Hibernate Commons Annotations {4.0.1.Final}
13:03:17,291 INFO  [org.hibernate.Version] (ajp--192.168.1.150-9081-2) HHH000412: Hibernate Core {4.0.1.Final}
13:03:17,293 INFO  [org.hibernate.cfg.Environment] (ajp--192.168.1.150-9081-2) HHH000206: hibernate.properties not found
13:03:17,295 INFO  [org.hibernate.cfg.Environment] (ajp--192.168.1.150-9081-2) HHH000021: Bytecode provider name : javassist
13:03:17,330 WARN  [org.hibernate.internal.util.xml.DTDEntityResolver] (ajp--192.168.1.150-9081-2) HHH000223: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/. Use namespace http://www.hibernate.org/dtd/ instead. Refer to Hibernate 3.6 Migration Guide!
13:03:17,523 INFO  [org.hibernate.dialect.Dialect] (ajp--192.168.1.150-9081-2) HHH000400: Using dialect: org.hibernate.dialect.Oracle10gDialect
13:03:17,543 INFO  [org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory] (ajp--192.168.1.150-9081-2) HHH000397: Using ASTQueryTranslatorFactory
13:03:17,581 INFO  [org.hibernate.validator.util.Version] (ajp--192.168.1.150-9081-2) Hibernate Validator 4.2.0.Final
13:03:18,134 INFO  [stdout] (ajp--192.168.1.150-9081-4) INSERT 1fhk6fys4sd6j 9363
13:03:18,135 INFO  [stdout] (ajp--192.168.1.150-9081-8) INSERT re87jkorw73z 9832
13:03:18,141 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 1ndgkrn77u2it 9820
13:03:18,142 INFO  [stdout] (ajp--192.168.1.150-9081-5) INSERT 1w2cp0u6lk89x 3356
13:03:18,143 INFO  [stdout] (ajp--192.168.1.150-9081-3) INSERT 17rjkpgd9eez9 5957
13:03:18,151 INFO  [stdout] (ajp--192.168.1.150-9081-9) UPDATE 1ke3x8flbzh2l 2468
13:03:18,152 INFO  [stdout] (ajp--192.168.1.150-9081-2) UPDATE b0hsnirgzegu 3428
13:03:18,208 INFO  [stdout] (ajp--192.168.1.150-9081-11) UPDATE 346ubsid1bcj 5107
13:03:18,217 INFO  [stdout] (ajp--192.168.1.150-9081-10) INSERT hhq72mspnlm6 3525
13:03:18,226 INFO  [stdout] (ajp--192.168.1.150-9081-3) INSERT 18z5vn487oq68 1145
13:03:18,229 INFO  [stdout] (ajp--192.168.1.150-9081-8) UPDATE 1g2v0qag7awbe 9292
13:03:18,241 INFO  [stdout] (ajp--192.168.1.150-9081-10) UPDATE 1iedrjwclb888 5015
13:03:18,244 INFO  [stdout] (ajp--192.168.1.150-9081-3) UPDATE h4nv7n4u4imi 431
13:03:18,256 INFO  [stdout] (ajp--192.168.1.150-9081-10) INSERT 146qoll1n1jpt 1994
13:03:18,265 INFO  [stdout] (ajp--192.168.1.150-9081-10) UPDATE sca0ze1e6a55 4618
13:03:18,273 INFO  [stdout] (ajp--192.168.1.150-9081-10) UPDATE neyi37tgskek 7683
13:03:18,331 INFO  [stdout] (ajp--192.168.1.150-9081-10) UPDATE 1itpm85ux9vu8 8101
13:03:18,344 INFO  [stdout] (ajp--192.168.1.150-9081-3) UPDATE 1hzxrlkqyxwvz 2642
13:03:18,350 INFO  [stdout] (ajp--192.168.1.150-9081-11) INSERT 1qsg68xingq39 5017
13:03:18,365 INFO  [stdout] (ajp--192.168.1.150-9081-8) INSERT 1a42lp62sxldw 6196
13:03:18,365 INFO  [stdout] (ajp--192.168.1.150-9081-10) UPDATE 1sd2tjmkikrwd 3633
13:03:18,368 INFO  [stdout] (ajp--192.168.1.150-9081-11) UPDATE 12326fhs1lgs6 1466
13:03:18,369 INFO  [stdout] (ajp--192.168.1.150-9081-3) INSERT 8z47zy6uo0lr 9042

JMS

Let us add some messaging as well. To this end, we add the following to the Spring configuration

<beans ...>
    <bean id="company" class="model.logic.CompanyBean">
        ...
        <property name="jmsTemplate" ref="jmstemplate"/>
    </bean>
	...
    <jee:jndi-lookup id="connectionfactory" jndi-name="java:/ConnectionFactory" resource-ref="false"/>
    <jee:jndi-lookup id="destination" jndi-name="java:/queue/test" resource-ref="false"/>
    <bean id="jmstemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionfactory"/>
        <property name="defaultDestination" ref="destination"/>
    </bean>
    <bean class="org.springframework.jms.listener.SimpleMessageListenerContainer">
        <property name="connectionFactory" ref="connectionfactory"/>
        <property name="destination" ref="destination"/>
        <property name="messageListener" ref="companymdp"/>
    </bean>
    <bean id="companymdp" class="model.logic.CompanyMDP"/>
</beans>

To send messages we edit the CompanyBean class as follows, i.e., add a property called jmsTemplate, add a method sendMessage that is called from the insertPerson and removePerson methods

package model.logic;

import model.entities.Person;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;

@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public class CompanyBean implements Company {

    private SessionFactory sessionFactory;
	private JmsTemplate jmsTemplate;

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public JmsTemplate getJmsTemplate() {
        return jmsTemplate;
    }

    public void setJmsTemplate(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    public void insertPerson(Person person) {
        Person temporaryPerson = findPerson(person.getSofinummer());
        if (temporaryPerson == null) {
            System.out.println("INSERT " + person);
            getCurrentSession().save(person);
            sendMessage(person);
        } else {
            updatePerson(person);
        }
    }

    public void removePerson(Integer sofinummer) {
        Person temporaryPerson = findPerson(sofinummer);
        if (temporaryPerson != null) {
            System.out.println("REMOVE " + temporaryPerson);
            getCurrentSession().delete(temporaryPerson);
            sendMessage(temporaryPerson);
        }
    }

    public void updatePerson(Person person) {
        System.out.println("UPDATE " + person);
        getCurrentSession().merge(person);
    }

    private Person findPerson(Integer sofinummer) {
        return (Person) getCurrentSession().get(Person.class, sofinummer);
    }

    private final Session getCurrentSession() {
        return getSessionFactory().getCurrentSession();
    }

    private void sendMessage(final Person person) {
        getJmsTemplate().send(new MessageCreator(){
            public Message createMessage(javax.jms.Session session) throws JMSException {
                ObjectMessage message = session.createObjectMessage();
                message.setObject(person);
                return message;
            }
        });
    }
}

Before we can deploy the application, we have to make sure the javax.jms.api module is added to the org.springframework module, i.e.,

<module xmlns="urn:jboss:module:1.1" name="org.springframework">
    <resources>
	<resource-root path="aopalliance-1.0.jar"/>
	<resource-root path="cglib-2.2.2.jar"/>
	<resource-root path="commons-logging-1.0.4.jar"/>
	<resource-root path="org.springframework.aop-3.1.2.RELEASE.jar"/>
	<resource-root path="org.springframework.asm-3.1.2.RELEASE.jar"/>
	<resource-root path="org.springframework.beans-3.1.2.RELEASE.jar"/>
	<resource-root path="org.springframework.context-3.1.2.RELEASE.jar"/>
	<resource-root path="org.springframework.core-3.1.2.RELEASE.jar"/>
	<resource-root path="org.springframework.expression-3.1.2.RELEASE.jar"/>
	<resource-root path="org.springframework.jdbc-3.1.2.RELEASE.jar"/>
	<resource-root path="org.springframework.jms-3.1.2.RELEASE.jar"/>
	<resource-root path="org.springframework.orm-3.1.2.RELEASE.jar"/>
	<resource-root path="org.springframework.transaction-3.1.2.RELEASE.jar"/>
	<resource-root path="org.springframework.web-3.1.2.RELEASE.jar"/>
    </resources>
    <dependencies>
        <module name="javax.api" export="true"/>
        <module name="org.apache.log4j" export="true"/>
        <module name="org.antlr" export="true"/>
        <module name="org.dom4j" export="true"/>
        <module name="org.hibernate" export="true"/>
        <module name="javax.persistence.api" export="true"/>
        <module name="org.javassist" export="true"/>
        <module name="org.jboss.logging" export="true"/>
        <module name="javax.transaction.api" export="true"/>
        <module name="javax.jms.api" export="true"/>
    </dependencies>
</module>

With the module in place, restart the servers and deploy the application, i.e.,

[domain@192.168.1.150:9999 /] undeploy SpringHibernate.war --server-groups=cluster-group
[domain@192.168.1.150:9999 /] /host=jboss/server-config=cluster-server2:restart
{
    "outcome" => "success",
    "result" => "STARTING"
}
[domain@192.168.1.150:9999 /] /host=jboss/server-config=cluster-server1:restart
{
    "outcome" => "success",
    "result" => "STARTING"
}
[domain@192.168.1.150:9999 /] deploy /home/jboss/jboss-as-7.1.0.Final/deploy/springhibernate/SpringHibernate.war --server-groups=cluster-group

The application can be reached at http://192.168.1.150:8888/SpringHibernate/testservlet. After doing a few requests the following is observed in the logging:

# LOGGING CLUSTER-SERVER1
15:45:13,723 INFO  [org.springframework.context.support.ClassPathXmlApplicationContext] (ajp--192.168.1.150-9080-5) Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1b7fc253: startup date [Tue Aug 14 15:45:13 CEST 2012]; root of context hierarchy
15:45:13,760 INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (ajp--192.168.1.150-9080-5) Loading XML bean definitions from class path resource [spring-config.xml]
15:45:14,119 INFO  [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer] (ajp--192.168.1.150-9080-5) Loading properties file from class path resource [spring.properties]
15:45:14,141 INFO  [org.springframework.beans.factory.support.DefaultListableBeanFactory] (ajp--192.168.1.150-9080-5) Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@411167f3: defining beans [company,sessionfactory,datasource,propertyConfigurer,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,connectionfactory,destination,jmstemplate,org.springframework.jms.listener.SimpleMessageListenerContainer#0,companymdp]; root of factory hierarchy
15:45:14,204 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp--192.168.1.150-9080-5) Using JTA UserTransaction: org.jboss.tm.usertx.client.ServerVMClientUserTransaction@539546ee
15:45:14,204 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp--192.168.1.150-9080-5) Using JTA TransactionManager: com.arjuna.ats.jbossatx.jta.TransactionManagerDelegate@3839029b
15:45:14,205 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp--192.168.1.150-9080-5) Using JTA TransactionSynchronizationRegistry: com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple@2818de48
15:45:14,291 INFO  [org.hibernate.annotations.common.Version] (ajp--192.168.1.150-9080-5) HCANN000001: Hibernate Commons Annotations {4.0.1.Final}
15:45:14,296 INFO  [org.hibernate.Version] (ajp--192.168.1.150-9080-5) HHH000412: Hibernate Core {4.0.1.Final}
15:45:14,297 INFO  [org.hibernate.cfg.Environment] (ajp--192.168.1.150-9080-5) HHH000206: hibernate.properties not found
15:45:14,299 INFO  [org.hibernate.cfg.Environment] (ajp--192.168.1.150-9080-5) HHH000021: Bytecode provider name : javassist
15:45:14,332 WARN  [org.hibernate.internal.util.xml.DTDEntityResolver] (ajp--192.168.1.150-9080-5) HHH000223: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/. Use namespace http://www.hibernate.org/dtd/ instead. Refer to Hibernate 3.6 Migration Guide!
15:45:14,549 INFO  [org.hibernate.dialect.Dialect] (ajp--192.168.1.150-9080-5) HHH000400: Using dialect: org.hibernate.dialect.Oracle10gDialect
15:45:14,567 INFO  [org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory] (ajp--192.168.1.150-9080-5) HHH000397: Using ASTQueryTranslatorFactory
15:45:14,603 INFO  [org.hibernate.validator.util.Version] (ajp--192.168.1.150-9080-5) Hibernate Validator 4.2.0.Final
15:45:14,957 INFO  [org.springframework.context.support.DefaultLifecycleProcessor] (ajp--192.168.1.150-9080-5) Starting beans in phase 2147483647
15:45:15,124 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT fe1g8llttlid 9594
15:45:15,185 INFO  [stdout] (Thread-1 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE fe1g8llttlid 9594
15:47:17,962 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE 1ruzaxp3ovrza 5434
15:47:18,507 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 13uem5a3s0tr0 4176
15:47:18,555 INFO  [stdout] (Thread-2 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE 13uem5a3s0tr0 4176
15:47:18,573 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT o0on52y2q6rc 7154
15:47:18,581 INFO  [stdout] (Thread-2 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE o0on52y2q6rc 7154
15:47:18,686 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE ji9vigyqm6tn 1580
15:47:18,721 INFO  [stdout] (ajp--192.168.1.150-9080-2) INSERT 501w5lrllrl1 6984
15:47:18,734 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE 501w5lrllrl1 6984
15:47:18,795 INFO  [stdout] (ajp--192.168.1.150-9080-2) INSERT q8i3p3v69ta9 9696
15:47:18,808 INFO  [stdout] (Thread-1 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE q8i3p3v69ta9 9696
15:47:18,870 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE 187qlr278gvk2 7989
15:47:18,944 INFO  [stdout] (ajp--192.168.1.150-9080-2) INSERT af0n7nhmhtn4 7354
15:47:18,954 INFO  [stdout] (Thread-1 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE af0n7nhmhtn4 7354
15:47:19,773 INFO  [stdout] (ajp--192.168.1.150-9080-2) INSERT 1rki73vjyxick 4429
15:47:19,797 INFO  [stdout] (Thread-2 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE 1rki73vjyxick 4429
15:47:19,805 INFO  [stdout] (ajp--192.168.1.150-9080-2) INSERT 7t977akfo2gv 6383
15:47:19,813 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE 7t977akfo2gv 6383
15:47:20,265 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 18nupcmjbywyz 9416
15:47:20,272 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE 18nupcmjbywyz 9416
15:47:20,288 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE ul6rda8yg61u 1891
15:47:20,298 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE 1fotcalk9shsq 1717
15:47:20,306 INFO  [stdout] (ajp--192.168.1.150-9080-2) INSERT fz2zkhr4bw9g 4969
15:47:20,330 INFO  [stdout] (Thread-2 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE fz2zkhr4bw9g 4969
15:47:20,332 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT nqmx27r3vcoz 7686
15:47:20,357 INFO  [stdout] (ajp--192.168.1.150-9080-4) INSERT 14znb00a9jipx 363
15:47:20,374 INFO  [stdout] (Thread-1 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE nqmx27r3vcoz 7686
15:47:20,389 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE 14znb00a9jipx 363
15:47:20,426 INFO  [stdout] (ajp--192.168.1.150-9080-9) INSERT 8ptga7h7jpeb 6888
15:47:20,428 INFO  [stdout] (ajp--192.168.1.150-9080-7) UPDATE cuy0x72tv27s 4669
15:47:20,447 INFO  [stdout] (Thread-1 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE 8ptga7h7jpeb 6888
15:47:20,465 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 3mws48gl5lz8 4333
15:47:20,467 INFO  [stdout] (ajp--192.168.1.150-9080-4) INSERT tfcnb3v0zt7p 7984
15:47:20,477 INFO  [stdout] (ajp--192.168.1.150-9080-8) INSERT 1ahyu3xkspnxr 3201
15:47:20,496 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE 3mws48gl5lz8 4333
15:47:20,497 INFO  [stdout] (ajp--192.168.1.150-9080-6) UPDATE 137a6srifr1gz 8905
15:47:20,501 INFO  [stdout] (ajp--192.168.1.150-9080-10) UPDATE 16epgzgkpuhyl 3052
15:47:20,528 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE x59b33fx74ec 2535
15:47:20,528 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE 1ahyu3xkspnxr 3201
15:47:20,531 INFO  [stdout] (ajp--192.168.1.150-9080-7) INSERT wkl0ag7vz56k 8274
15:47:20,537 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE tfcnb3v0zt7p 7984
15:47:20,543 INFO  [stdout] (Thread-4 (HornetQ-client-global-threads-1978193102)) RECEIVED OBJECT MESSAGE wkl0ag7vz56k 8274
# LOGGING CLUSTER-SERVER2
15:47:18,658 INFO  [org.springframework.context.support.ClassPathXmlApplicationContext] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@28b3cf4a: startup date [Tue Aug 14 15:47:18 CEST 2012]; root of context hierarchy
15:47:18,696 INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) Loading XML bean definitions from class path resource [spring-config.xml]
15:47:19,005 INFO  [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) Loading properties file from class path resource [spring.properties]
15:47:19,025 INFO  [org.springframework.beans.factory.support.DefaultListableBeanFactory] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@3ff39e73: defining beans [company,sessionfactory,datasource,propertyConfigurer,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,connectionfactory,destination,jmstemplate,org.springframework.jms.listener.SimpleMessageListenerContainer#0,companymdp]; root of factory hierarchy
15:47:19,087 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) Using JTA UserTransaction: org.jboss.tm.usertx.client.ServerVMClientUserTransaction@5935b50c
15:47:19,088 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) Using JTA TransactionManager: com.arjuna.ats.jbossatx.jta.TransactionManagerDelegate@5b33a7af
15:47:19,090 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) Using JTA TransactionSynchronizationRegistry: com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple@54cf76c8
15:47:19,177 INFO  [org.hibernate.annotations.common.Version] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) HCANN000001: Hibernate Commons Annotations {4.0.1.Final}
15:47:19,182 INFO  [org.hibernate.Version] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) HHH000412: Hibernate Core {4.0.1.Final}
15:47:19,184 INFO  [org.hibernate.cfg.Environment] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) HHH000206: hibernate.properties not found
15:47:19,186 INFO  [org.hibernate.cfg.Environment] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) HHH000021: Bytecode provider name : javassist
15:47:19,221 WARN  [org.hibernate.internal.util.xml.DTDEntityResolver] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) HHH000223: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/. Use namespace http://www.hibernate.org/dtd/ instead. Refer to Hibernate 3.6 Migration Guide!
15:47:19,433 INFO  [org.hibernate.dialect.Dialect] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) HHH000400: Using dialect: org.hibernate.dialect.Oracle10gDialect
15:47:19,454 INFO  [org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) HHH000397: Using ASTQueryTranslatorFactory
15:47:19,486 INFO  [org.hibernate.validator.util.Version] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) Hibernate Validator 4.2.0.Final
15:47:19,893 INFO  [org.springframework.context.support.DefaultLifecycleProcessor] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) Starting beans in phase 2147483647
15:47:20,126 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-5) INSERT 1uygcxcowtu9a 331
15:47:20,127 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-6) INSERT mow4srfubly0 6092
15:47:20,180 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-4) INSERT 45ctomltbfnj 7350
15:47:20,182 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-3) INSERT 2bfcfctogwas 9945
15:47:20,186 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-2) INSERT 1ghndct2k38fq 7215
15:47:20,190 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-8) UPDATE 1q6wykxdwe57w 8885
15:47:20,191 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-9) UPDATE edte8od9xrou 4704
15:47:20,192 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-10) UPDATE 1adm2wi7sosp0 3801
15:47:20,194 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-11) INSERT 1cof2wpo05qux 8205
15:47:20,195 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-7) INSERT 1jq47i7b26tvp 609
15:47:20,307 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-7) INSERT 1qxeatjtlqzx5 3722
15:47:20,313 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-12) UPDATE cztialmryr6t 2306
15:47:20,323 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-699447810)) RECEIVED OBJECT MESSAGE 45ctomltbfnj 7350
15:47:20,335 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-3) UPDATE s964r48d3sen 6153
15:47:20,343 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-8) UPDATE g9jng4dhqtha 8360
15:47:20,359 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-12) INSERT 1fs7d2l62ags4 9334
15:47:20,363 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-699447810)) RECEIVED OBJECT MESSAGE 1ghndct2k38fq 7215
15:47:20,372 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-8) UPDATE 1fac6z0zdhxfo 4796
15:47:20,377 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-699447810)) RECEIVED OBJECT MESSAGE 1jq47i7b26tvp 609
15:47:20,378 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-5) UPDATE 1vkso90xvg1kf 3038
15:47:20,381 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-3) INSERT b5jtmtrok3ay 9950
15:47:20,385 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-12) INSERT 1eob8au4ivjaq 7646
15:47:20,394 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-699447810)) RECEIVED OBJECT MESSAGE 1uygcxcowtu9a 331
15:47:20,400 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-5) INSERT g3tpmc15n1pw 7940
15:47:20,403 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-699447810)) RECEIVED OBJECT MESSAGE 1cof2wpo05qux 8205
15:47:20,412 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-699447810)) RECEIVED OBJECT MESSAGE mow4srfubly0 6092
15:47:20,419 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-699447810)) RECEIVED OBJECT MESSAGE 2bfcfctogwas 9945
15:47:20,421 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-5) INSERT ub7uqkgxgvkn 7389
15:47:20,423 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-699447810)) RECEIVED OBJECT MESSAGE 1qxeatjtlqzx5 3722
15:47:20,433 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-699447810)) RECEIVED OBJECT MESSAGE 1fs7d2l62ags4 9334
15:47:20,437 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-12) INSERT 1o9uvk6v2q3yh 6427
15:47:20,445 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-699447810)) RECEIVED OBJECT MESSAGE b5jtmtrok3ay 9950
15:47:20,454 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-699447810)) RECEIVED OBJECT MESSAGE 1eob8au4ivjaq 7646
15:47:20,459 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-5) UPDATE ztxczcv9lczr 6350
15:47:20,467 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-699447810)) RECEIVED OBJECT MESSAGE g3tpmc15n1pw 7940
15:47:20,472 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-3) INSERT 1e50cqtnnx877 4627
15:47:20,492 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9081-12) INSERT gzgnffn3j4jv 7794
15:47:20,495 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-699447810)) RECEIVED OBJECT MESSAGE ub7uqkgxgvkn 7389
15:47:20,507 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-699447810)) RECEIVED OBJECT MESSAGE 1o9uvk6v2q3yh 6427
15:47:20,511 INFO  [stdout] (Thread-3 (HornetQ-client-global-threads-699447810)) RECEIVED OBJECT MESSAGE 1e50cqtnnx877 4627
15:47:20,520 INFO  [stdout] (Thread-1 (HornetQ-client-global-threads-699447810)) RECEIVED OBJECT MESSAGE gzgnffn3j4jv 7794

Transactions

In the example above we have used a SimpleMessageListenerContainer. A message listener container is used to receive messages from a JMS message queue and drive the MessageListener that is injected into it. The listener container is responsible for all threading of message reception and dispatches into the listener for processing. A message listener container is the intermediary between an MDP and a messaging provider, and takes care of registering to receive messages, participating in transactions, resource acquisition and release, exception conversion and suchlike. There are two standard JMS message listener containers packaged with Spring, each with its specialised feature set:

  • SimpleMessageListenerContainer – This message listener container is the simpler of the two standard flavors. It creates a fixed number of JMS sessions and consumers at startup, registers the listener using the standard JMS MessageConsumer.setMessageListener method, and leaves it up the JMS provider to perform listener callbacks. This variant does not allow for dynamic adaption to runtime demands or for participation in externally managed transactions. Compatibility-wise, it stays very close to the spirit of the standalone JMS specification – but is generally not compatible with Java EE’s JMS restrictions.
  • DefaultMessageListenerContainer – This message listener container is the one used in most cases. In contrast to SimpleMessageListenerContainer, this container variant does allow for dynamic adaption to runtime demands and is able to participate in externally managed transactions. Each received message is registered with an XA transaction when configured with a JtaTransactionManager; so processing may take advantage of XA transaction semantics. This listener container strikes a good balance between low requirements on the JMS provider, advanced functionality such as transaction participation, and compatibility with Java EE environments.

To use the second flavor in our set-up, we can change the Spring configuration to

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
    <bean id="company" class="model.logic.CompanyBean">
        <property name="sessionFactory" ref="sessionfactory"/>
        <property name="jmsTemplate" ref="jmstemplate"/>
    </bean>
	<!-- Hibernate SessionFactory config -->
    <bean id="sessionfactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="datasource"/>
        <property name="jtaTransactionManager" ref="transactionManager"/>
        <property name="mappingResources">
            <list>
                <value>model/entities/person.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.current_session_context_class">${hibernate.current_session_context_class}</prop>
                <prop key="hibernate.listeners.envers.autoRegister">${hibernate.listeners.envers.autoRegister}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
            </props>
        </property>
    </bean>
	<!-- Transaction config -->
	<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
	<tx:annotation-driven transaction-manager="transactionManager"/>
	<!-- Resource look-ups -->
    <jee:jndi-lookup id="datasource" jndi-name="java:/jdbc/OracleDS" resource-ref="false"/>
    <jee:jndi-lookup id="connectionfactory" jndi-name="java:/JmsXA" resource-ref="false"/>
    <jee:jndi-lookup id="destination" jndi-name="java:/queue/test" resource-ref="false"/>
    <!-- JMS config -->
	<bean id="jmstemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionfactory"/>
        <property name="defaultDestination" ref="destination"/>
    </bean>
    <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionfactory"/>
        <property name="destination" ref="destination"/>
        <property name="transactionManager" ref="transactionManager"/>
        <property name="messageListener" ref="companymdp"/>
    </bean>
    <bean id="companymdp" class="model.logic.CompanyMDP"/>
	<!-- Extra -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:spring.properties</value>
            </list>
        </property>
    </bean>
</beans>

Note that code remains as it was. We have used the following JBoss configuration that shows how the used resources are configured

<domain xmlns="urn:jboss:domain:1.1">
	...
    <profiles>
        <profile name="cluster">
            <subsystem xmlns="urn:jboss:domain:datasources:1.0">
                <datasources>
                    <datasource jta="true" jndi-name="java:/jdbc/OracleDS" pool-name="OracleDS" enabled="true" use-java-context="true" use-ccm="true">
                        <connection-url>jdbc:oracle:thin:@192.168.1.60:1521:orcl11</connection-url>
                        <driver>oracle</driver>
                        <pool>
                            <min-pool-size>1</min-pool-size>
                            <max-pool-size>15</max-pool-size>
                            <prefill>true</prefill>
                            <use-strict-min>true</use-strict-min>
                        </pool>
                        <security>
                            <user-name>example</user-name>
                            <password>example</password>
                        </security>
                        <timeout>
                            <idle-timeout-minutes>0</idle-timeout-minutes>
                            <query-timeout>600</query-timeout>
                        </timeout>
                        <statement>
                            <prepared-statement-cache-size>10</prepared-statement-cache-size>
                        </statement>
                    </datasource>
                    <drivers>
                        <driver name="oracle" module="com.oracle.database">
                            <driver-class>oracle.jdbc.OracleDriver</driver-class>
                            <xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>
                        </driver>
                    </drivers>
                </datasources>
            </subsystem>
            <subsystem xmlns="urn:jboss:domain:messaging:1.1">
                <hornetq-server>
					...
                    <jms-connection-factories>
						...
                        <pooled-connection-factory name="hornetq-ra">
                            <transaction mode="xa"/>
                            <connectors>
                                <connector-ref connector-name="in-vm"/>
                            </connectors>
                            <entries>
                                <entry name="java:/JmsXA"/>
                            </entries>
                        </pooled-connection-factory>
                    </jms-connection-factories>
                    <jms-destinations>
                        <jms-queue name="testQueue">
                            <entry name="java:/queue/test"/>
                            <entry name="java:jboss/exported/jms/queue/test"/>
                        </jms-queue>
						...
                    </jms-destinations>
                </hornetq-server>
            </subsystem>
			...
        </profile>
    </profiles>
	...
    <deployments>
        <deployment name="LoadTest6.ear" runtime-name="LoadTest6.ear">
            <content sha1="161f51dde7f085c822cc4c68b306d57f1bee902d"/>
        </deployment>
        <deployment name="SpringHibernate.war" runtime-name="SpringHibernate.war">
            <content sha1="574d0617d92d8439844633557937be754a134370"/>
        </deployment>
    </deployments>
    <server-groups>
		...
        <server-group name="cluster-group" profile="cluster">
            <jvm name="default"/>
            <socket-binding-group ref="cluster-sockets"/>
            <deployments>
                <deployment name="LoadTest6.ear" runtime-name="LoadTest6.ear"/>
                <deployment name="SpringHibernate.war" runtime-name="SpringHibernate.war" enabled="false"/>
            </deployments>
        </server-group>
    </server-groups>
</domain>

Note that we have set the mode of the connection factory to XA (as is required when using the JtaTransactionManager and the DefaultMessageListenerContainer). One important thing to remember when using the DefaultMessageListenerContainer is that the default sessionAcknowledgeMode setting is AUTO_ACKNOWLEDGE (see here), so it not smart to use message.acknowledge in the MDP, otherwise we will run into

09:33:20,815 INFO  [org.springframework.context.support.ClassPathXmlApplicationContext] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@74359b24: startup date [Fri Aug 17 09:33:20 CEST 2012]; root of context hierarchy
09:33:20,945 INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) Loading XML bean definitions from class path resource [spring-config.xml]
09:33:21,415 INFO  [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) Loading properties file from class path resource [spring.properties]
09:33:21,441 INFO  [org.springframework.beans.factory.support.DefaultListableBeanFactory] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6c11e58: defining beans [company,sessionfactory,datasource,propertyConfigurer,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,connectionfactory,destination,jmstemplate,org.springframework.jms.listener.DefaultMessageListenerContainer#0,companymdp]; root of factory hierarchy
09:33:21,535 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) Using JTA UserTransaction: org.jboss.tm.usertx.client.ServerVMClientUserTransaction@7e0cf590
09:33:21,536 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) Using JTA TransactionManager: com.arjuna.ats.jbossatx.jta.TransactionManagerDelegate@4d50b06b
09:33:21,537 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) Using JTA TransactionSynchronizationRegistry: com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple@38d060ac
09:33:21,784 INFO  [org.hibernate.annotations.common.Version] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) HCANN000001: Hibernate Commons Annotations {4.0.1.Final}
09:33:21,792 INFO  [org.hibernate.Version] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) HHH000412: Hibernate Core {4.0.1.Final}
09:33:21,794 INFO  [org.hibernate.cfg.Environment] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) HHH000206: hibernate.properties not found
09:33:21,796 INFO  [org.hibernate.cfg.Environment] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) HHH000021: Bytecode provider name : javassist
09:33:21,907 WARN  [org.hibernate.internal.util.xml.DTDEntityResolver] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) HHH000223: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/. Use namespace http://www.hibernate.org/dtd/ instead. Refer to Hibernate 3.6 Migration Guide!
09:33:22,517 INFO  [org.hibernate.dialect.Dialect] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) HHH000400: Using dialect: org.hibernate.dialect.Oracle10gDialect
09:33:22,539 INFO  [org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) HHH000397: Using ASTQueryTranslatorFactory
09:33:22,652 INFO  [org.hibernate.validator.util.Version] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) Hibernate Validator 4.2.0.Final
09:33:23,152 INFO  [org.springframework.context.support.DefaultLifecycleProcessor] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) Starting beans in phase 2147483647
09:33:23,552 INFO  [stdout] (ajp-axis-into-ict.nl-192.168.1.150-9080-7) INSERT 1chrw6b78f2w9 9719
09:33:23,671 WARN  [org.springframework.jms.listener.DefaultMessageListenerContainer] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) Execution of JMS message listener failed, and no ErrorHandler has been set.: java.lang.RuntimeException: javax.jms.IllegalStateException: Non XA connection
    at model.logic.CompanyMDP.onMessage(CompanyMDP.java:16) [classes:]
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:562) [org.springframework.jms-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:500) [org.springframework.jms-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:468) [org.springframework.jms-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:326) [org.springframework.jms-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:244) [org.springframework.jms-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1071) [org.springframework.jms-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1063) [org.springframework.jms-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:960) [org.springframework.jms-3.1.2.RELEASE.jar:3.1.2.RELEASE]
    at java.lang.Thread.run(Thread.java:662) [rt.jar:1.6.0_31]
Caused by: javax.jms.IllegalStateException: Non XA connection
    at org.hornetq.ra.HornetQRASession.getSession(HornetQRASession.java:1246)
    at org.hornetq.ra.HornetQRAMessage.acknowledge(HornetQRAMessage.java:71)
    at model.logic.CompanyMDP.onMessage(CompanyMDP.java:13) [classes:]
    ... 9 more

Another thing worth mentioning is that within a JTA transaction, the parameters passed to create(Queue/Topic)Session(boolean transacted, int acknowledgeMode) method are not taken into account. Depending on the JavaEE transaction context, the container makes its own decisions on these values.

Let us deploy the application again and see what happens:

# LOGGING CLUSTER SERVER 1
14:03:01,180 INFO  [org.jboss.as.webservices] (ServerService Thread Pool -- 32) JBAS015537: Activating WebServices Extension
14:03:01,242 INFO  [org.jboss.as.security] (ServerService Thread Pool -- 36) JBAS013101: Activating Security Subsystem
14:03:01,245 INFO  [org.jboss.as.security] (MSC service thread 1-1) JBAS013100: Current PicketBox version=4.0.6.final
14:03:01,359 INFO  [org.jboss.as.naming] (ServerService Thread Pool -- 42) JBAS011800: Activating Naming Subsystem
14:03:01,420 INFO  [org.jboss.as.osgi] (ServerService Thread Pool -- 41) JBAS011940: Activating OSGi Subsystem
14:03:01,491 INFO  [org.jboss.as.naming] (MSC service thread 1-3) JBAS011802: Starting Naming Service
14:03:01,508 INFO  [org.jboss.as.mail.extension] (MSC service thread 1-3) JBAS015400: Bound mail session [java:jboss/mail/Default]
14:03:01,628 INFO  [org.jboss.as.clustering.jgroups] (ServerService Thread Pool -- 49) JBAS010260: Activating JGroups subsystem.
14:03:01,792 INFO  [org.jboss.as.clustering.infinispan] (ServerService Thread Pool -- 55) JBAS010280: Activating Infinispan subsystem.
14:03:01,813 INFO  [org.jboss.as.jacorb] (ServerService Thread Pool -- 54) JBAS016300: Activating JacORB Subsystem
14:03:01,883 INFO  [org.jboss.as.connector.subsystems.datasources] (ServerService Thread Pool -- 58) JBAS010403: Deploying JDBC-compliant driver class org.h2.Driver (version 1.3)
14:03:01,894 INFO  [org.jboss.as.configadmin] (ServerService Thread Pool -- 59) JBAS016200: Activating ConfigAdmin Subsystem
14:03:01,913 INFO  [org.jboss.ws.common.management.AbstractServerConfig] (MSC service thread 1-3) JBoss Web Services - Stack CXF Server 4.0.1.GA
14:03:02,259 INFO  [org.jboss.as.connector.subsystems.datasources] (ServerService Thread Pool -- 58) JBAS010403: Deploying JDBC-compliant driver class oracle.jdbc.OracleDriver (version 11.2)
14:03:02,275 INFO  [org.jboss.as.modcluster] (MSC service thread 1-2) JBAS011704: Mod_cluster uses default load balancer provider
14:03:02,389 INFO  [org.apache.coyote.http11.Http11AprProtocol] (MSC service thread 1-3) Starting Coyote HTTP/1.1 on http--192.168.1.150-8080
14:03:02,413 INFO  [org.jboss.modcluster.ModClusterService] (MSC service thread 1-2) Initializing mod_cluster 1.2.0.Final
14:03:02,471 INFO  [org.apache.coyote.ajp.AjpAprProtocol] (MSC service thread 1-4) Starting Coyote AJP/1.3 on ajp--192.168.1.150-9080
14:03:02,515 INFO  [org.jboss.as.connector] (MSC service thread 1-3) JBAS010408: Starting JCA Subsystem (JBoss IronJacamar 1.0.7.Final)
14:03:02,551 INFO  [org.jboss.modcluster.advertise.impl.AdvertiseListenerImpl] (MSC service thread 1-2) Listening to proxy advertisements on 224.0.1.105:23364
14:03:02,700 INFO  [org.jboss.as.jaxr] (MSC service thread 1-1) Binding JAXR ConnectionFactory: java:jboss/jaxr/ConnectionFactory
14:03:03,010 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-1) live server is starting with configuration HornetQ Configuration (clustered=false,backup=false,sharedStore=true,journalDirectory=/home/jboss/jboss-as-7.1.0.Final/domain/servers/cluster-server1/data/messagingjournal,bindingsDirectory=/home/jboss/jboss-as-7.1.0.Final/domain/servers/cluster-server1/data/messagingbindings,largeMessagesDirectory=/home/jboss/jboss-as-7.1.0.Final/domain/servers/cluster-server1/data/messaginglargemessages,pagingDirectory=/home/jboss/jboss-as-7.1.0.Final/domain/servers/cluster-server1/data/messagingpaging)
14:03:03,012 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-1) Waiting to obtain live lock
14:03:03,064 INFO  [org.infinispan.configuration.cache.EvictionConfigurationBuilder] (ServerService Thread Pool -- 55) ISPN000152: Passivation configured without an eviction policy being selected. Only manually evicted entities will be pasivated.
14:03:03,244 INFO  [org.hornetq.core.persistence.impl.journal.JournalStorageManager] (MSC service thread 1-1) Using AIO Journal
14:03:03,256 INFO  [org.infinispan.configuration.cache.EvictionConfigurationBuilder] (ServerService Thread Pool -- 55) ISPN000152: Passivation configured without an eviction policy being selected. Only manually evicted entities will be pasivated.
14:03:03,673 INFO  [org.jboss.as.jacorb] (MSC service thread 1-3) JBAS016330: CORBA ORB Service started
14:03:03,741 INFO  [org.hornetq.core.server.impl.AIOFileLockNodeManager] (MSC service thread 1-1) Waiting to obtain live lock
14:03:03,742 INFO  [org.hornetq.core.server.impl.AIOFileLockNodeManager] (MSC service thread 1-1) Live Server Obtained live lock
14:03:04,099 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-4) JBAS010400: Bound data source [java:jboss/datasources/ExampleDS]
14:03:04,107 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-2) JBAS010400: Bound data source [java:/jdbc/OracleDS]
14:03:04,133 INFO  [org.jboss.as.jacorb] (MSC service thread 1-3) JBAS016328: CORBA Naming Service started
14:03:04,698 INFO  [org.jboss.as.remoting] (MSC service thread 1-3) JBAS017100: Listening on axis-into-ict.nl/192.168.1.150:4447
14:03:05,157 INFO  [org.hornetq.core.remoting.impl.netty.NettyAcceptor] (MSC service thread 1-1) Started Netty Acceptor version 3.2.5.Final-a96d88c axis-into-ict.nl:5445 for CORE protocol
14:03:05,158 INFO  [org.hornetq.core.remoting.impl.netty.NettyAcceptor] (MSC service thread 1-1) Started Netty Acceptor version 3.2.5.Final-a96d88c axis-into-ict.nl:5455 for CORE protocol
14:03:05,159 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-1) Server is now live
14:03:05,160 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-1) HornetQ Server version 2.2.11.Final (HQ_2_2_11_FINAL_AS7, 122) [2e926cad-78e4-11e1-b1c7-000c2976c82d]) started
14:03:05,166 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-1) trying to deploy queue jms.queue.testQueue
14:03:05,180 INFO  [org.jboss.as.messaging] (MSC service thread 1-1) JBAS011601: Bound messaging object to jndi name java:jboss/exported/jms/queue/test
14:03:05,181 INFO  [org.jboss.as.messaging] (MSC service thread 1-1) JBAS011601: Bound messaging object to jndi name java:/queue/test
14:03:05,210 INFO  [org.jboss.as.messaging] (MSC service thread 1-4) JBAS011601: Bound messaging object to jndi name java:/ConnectionFactory
14:03:05,211 INFO  [org.jboss.as.messaging] (MSC service thread 1-3) JBAS011601: Bound messaging object to jndi name java:jboss/exported/jms/RemoteConnectionFactory
14:03:05,212 INFO  [org.jboss.as.messaging] (MSC service thread 1-3) JBAS011601: Bound messaging object to jndi name java:/RemoteConnectionFactory
14:03:05,213 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-2) trying to deploy queue jms.topic.testTopic
14:03:05,278 INFO  [org.jboss.as.messaging] (MSC service thread 1-2) JBAS011601: Bound messaging object to jndi name java:/topic/test
14:03:05,281 INFO  [org.jboss.as.messaging] (MSC service thread 1-2) JBAS011601: Bound messaging object to jndi name java:jboss/exported/jms/topic/test
14:03:05,288 INFO  [org.jboss.as.deployment.connector] (MSC service thread 1-3) JBAS010406: Registered connection factory java:/JmsXA
14:03:05,297 INFO  [org.hornetq.ra.HornetQResourceAdapter] (MSC service thread 1-3) HornetQ resource adaptor started
14:03:05,298 INFO  [org.jboss.as.connector.services.ResourceAdapterActivatorService$ResourceAdapterActivator] (MSC service thread 1-3) IJ020002: Deployed: file://RaActivatorhornetq-ra
14:03:05,309 INFO  [org.jboss.as.deployment.connector] (MSC service thread 1-4) JBAS010401: Bound JCA ConnectionFactory [java:/JmsXA]
14:03:05,397 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015874: JBoss AS 7.1.0.Final "Thunder" started in 7781ms - Started 169 of 292 services (121 services are passive or on-demand)
14:03:11,925 INFO  [org.jboss.modcluster.ModClusterService] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Engine [jboss.web] will use jvmRoute: 2c78c6e8-7325-3857-8bfc-d957f56114dc
14:04:34,838 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-2) JBAS015876: Starting deployment of "SpringHibernate.war"
14:04:35,410 INFO  [org.jboss.web] (MSC service thread 1-3) JBAS018210: Registering web context: /SpringHibernate
14:04:35,621 INFO  [org.jboss.as.server] (host-controller-connection-threads - 1) JBAS018559: Deployed "SpringHibernate.war"
14:05:11,613 INFO  [org.springframework.context.support.ClassPathXmlApplicationContext] (ajp--192.168.1.150-9080-7) Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@4e24faf1: startup date [Wed Aug 22 14:05:11 CEST 2012]; root of context hierarchy
14:05:11,651 INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (ajp--192.168.1.150-9080-7) Loading XML bean definitions from class path resource [spring-config.xml]
14:05:11,912 INFO  [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer] (ajp--192.168.1.150-9080-7) Loading properties file from class path resource [spring.properties]
14:05:11,932 INFO  [org.springframework.beans.factory.support.DefaultListableBeanFactory] (ajp--192.168.1.150-9080-7) Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@215a730d: defining beans [company,sessionfactory,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,datasource,connectionfactory,destination,jmstemplate,org.springframework.jms.listener.DefaultMessageListenerContainer#0,companymdp,propertyConfigurer]; root of factory hierarchy
14:05:11,990 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp--192.168.1.150-9080-7) Using JTA UserTransaction: org.jboss.tm.usertx.client.ServerVMClientUserTransaction@16360771
14:05:11,991 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp--192.168.1.150-9080-7) Using JTA TransactionManager: com.arjuna.ats.jbossatx.jta.TransactionManagerDelegate@76efb90
14:05:11,992 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp--192.168.1.150-9080-7) Using JTA TransactionSynchronizationRegistry: com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple@500c8efc
14:05:12,080 INFO  [org.hibernate.annotations.common.Version] (ajp--192.168.1.150-9080-7) HCANN000001: Hibernate Commons Annotations {4.0.1.Final}
14:05:12,084 INFO  [org.hibernate.Version] (ajp--192.168.1.150-9080-7) HHH000412: Hibernate Core {4.0.1.Final}
14:05:12,086 INFO  [org.hibernate.cfg.Environment] (ajp--192.168.1.150-9080-7) HHH000206: hibernate.properties not found
14:05:12,088 INFO  [org.hibernate.cfg.Environment] (ajp--192.168.1.150-9080-7) HHH000021: Bytecode provider name : javassist
14:05:12,124 WARN  [org.hibernate.internal.util.xml.DTDEntityResolver] (ajp--192.168.1.150-9080-7) HHH000223: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/. Use namespace http://www.hibernate.org/dtd/ instead. Refer to Hibernate 3.6 Migration Guide!
14:05:12,355 INFO  [org.hibernate.dialect.Dialect] (ajp--192.168.1.150-9080-7) HHH000400: Using dialect: org.hibernate.dialect.Oracle10gDialect
14:05:12,376 INFO  [org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory] (ajp--192.168.1.150-9080-7) HHH000397: Using ASTQueryTranslatorFactory
14:05:12,414 INFO  [org.hibernate.validator.util.Version] (ajp--192.168.1.150-9080-7) Hibernate Validator 4.2.0.Final
14:05:12,790 INFO  [org.springframework.context.support.DefaultLifecycleProcessor] (ajp--192.168.1.150-9080-7) Starting beans in phase 2147483647
14:05:12,921 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE tdq5p6nrua78 881
14:05:13,111 INFO  [stdout] (ajp--192.168.1.150-9080-7) INSERT 3zbulkvppaht 1587
14:05:13,192 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 3zbulkvppaht 1587
14:05:19,838 INFO  [stdout] (ajp--192.168.1.150-9080-7) INSERT 3677kx0gg6p8 3335
14:05:19,878 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 3677kx0gg6p8 3335
14:05:20,597 INFO  [stdout] (ajp--192.168.1.150-9080-7) UPDATE qd3nfb51iltt 5472
14:05:21,157 INFO  [stdout] (ajp--192.168.1.150-9080-7) INSERT 170gdo1t8e5ko 3391
14:05:21,225 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 170gdo1t8e5ko 3391
14:05:21,242 INFO  [stdout] (ajp--192.168.1.150-9080-6) INSERT 1vaezfdq5d887 5839
14:05:21,294 INFO  [stdout] (ajp--192.168.1.150-9080-3) UPDATE jlha13ox3hwq 4651
14:05:21,321 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1vaezfdq5d887 5839
14:05:21,368 INFO  [stdout] (ajp--192.168.1.150-9080-4) UPDATE s84z6ya9j2w5 65
14:05:21,443 INFO  [stdout] (ajp--192.168.1.150-9080-4) INSERT zsnamkv7f31q 4
14:05:21,505 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE zsnamkv7f31q 4
14:05:21,515 INFO  [stdout] (ajp--192.168.1.150-9080-2) INSERT 1f7y1xru7z3ol 1814
14:05:21,530 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1f7y1xru7z3ol 1814
14:05:21,589 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE 35fccgwsvlo0 2309
14:05:21,663 INFO  [stdout] (ajp--192.168.1.150-9080-2) INSERT u0sdivuxanqf 1574
14:05:21,680 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE u0sdivuxanqf 1574
14:05:21,740 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE h93lz8lmamwm 7188
14:05:21,811 INFO  [stdout] (ajp--192.168.1.150-9080-2) INSERT z03kievlq3ec 9039
14:05:21,866 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE z03kievlq3ec 9039
14:05:21,893 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE 1xfiowipw18ie 6334
14:05:21,960 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT t12jyo6mydxp 8628
14:05:21,995 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE t12jyo6mydxp 8628
14:05:22,035 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 1b7mtaj9ux4cf 6651
14:05:22,070 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1b7mtaj9ux4cf 6651
14:05:22,109 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 1497gjpwnx06e 5835
14:05:22,124 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1497gjpwnx06e 5835
14:05:22,182 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE jusago26clrr 470
14:05:22,257 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE cl3qbhtfb7ul 7990
14:05:22,330 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 1nvbqqb80m410 2000
14:05:22,377 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1nvbqqb80m410 2000
14:05:22,405 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT hfpwva5k7dgp 6255
14:05:22,439 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE hfpwva5k7dgp 6255
14:05:22,479 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE awkvfp0doliq 6581
14:05:22,553 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE 1xbh2guvpaeal 2005
14:05:22,627 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT bq62t89yksnl 7832
14:05:22,645 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE bq62t89yksnl 7832
14:05:22,701 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE 1v9cegaooyl7l 8801
14:05:22,778 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 5afihmfmz78m 8493
14:05:22,817 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 5afihmfmz78m 8493
14:05:22,886 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE 1u06cy6ymizsc 8529
14:05:22,961 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE cnj2vloagv7n 105
14:05:23,034 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 7knlbcrs35tv 4975
14:05:23,070 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 7knlbcrs35tv 4975
14:05:23,109 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE icaxkpdgtqix 8605
14:05:23,183 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT ib776bswgvgs 1069
14:05:23,199 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE ib776bswgvgs 1069
14:05:23,258 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE pfbjj6qrx0lk 4247
14:05:23,337 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 1flpyivctw575 7035
14:05:23,354 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1flpyivctw575 7035
14:05:23,408 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE hlot1fnb068s 1172
14:05:23,479 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT sz4k5gzq3jop 5815
14:05:23,495 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE sz4k5gzq3jop 5815
14:05:23,560 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT ay53hxwhydvt 1006
14:05:23,577 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE ay53hxwhydvt 1006
14:05:23,628 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE p8izdhg3kqwl 20
14:05:23,702 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE 1cbvcvwojd9r1 4816
14:05:23,776 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT bdeoggzsp10b 3061
14:05:23,834 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE bdeoggzsp10b 3061
14:05:23,851 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE tpkz5b3l2qxg 3116
14:05:23,925 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE 9egiwbb1zqtk 9439
14:05:24,002 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE pebum5s3v56r 7314
14:05:24,072 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 5tvfzpub30ea 1084
14:05:24,091 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 5tvfzpub30ea 1084
14:05:24,147 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE 1pf8pteh26ykp 3161
14:05:24,225 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 3ze6zl91gz7b 916
14:05:24,276 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 3ze6zl91gz7b 916
14:05:24,295 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE zu9klw0bi6wd 1375
14:05:24,369 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE 1wf30ovze2jtf 1643
14:05:24,443 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 3evnoqlt6oag 4807
14:05:24,464 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 3evnoqlt6oag 4807
14:05:24,517 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT jixj7dxjn3bp 6387
14:05:24,532 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE jixj7dxjn3bp 6387
14:05:24,592 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT a01r5mb9ldf4 6501
14:05:24,620 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE a01r5mb9ldf4 6501
14:05:24,665 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE 18w9pp8mdk461 2853
14:05:24,740 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE devujxahhtzj 4128
14:05:24,814 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 1i88goa3n83oh 4485
14:05:24,837 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1i88goa3n83oh 4485
14:05:24,888 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE 43shzvb5wlak 4168
14:05:24,963 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT t6gc6fxquz4m 1388
14:05:24,986 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE t6gc6fxquz4m 1388
14:05:25,036 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE qklpn5ve0ozp 2928
14:05:25,111 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE 1nrm8lmgk26hp 7968
14:05:25,184 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE pdby3n7ae41s 8360
14:05:25,259 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT leqaa72xl4gm 810
14:05:25,274 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE leqaa72xl4gm 810
14:05:25,332 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 1xyro8op0a0f3 4288
14:05:25,349 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1xyro8op0a0f3 4288
14:05:25,407 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 1c12hea4x2acw 7731
14:05:25,451 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1c12hea4x2acw 7731
14:05:25,481 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT rzlgra4tco9e 8689
14:05:25,541 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE rzlgra4tco9e 8689
14:05:25,555 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 1j7f10xaqfmv5 298
14:05:25,598 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1j7f10xaqfmv5 298
14:05:25,629 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 1nah1yqhlz161 9179
14:05:25,662 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1nah1yqhlz161 9179
14:05:25,703 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE r8txbotr8vav 8849
14:05:25,778 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 1g6cybvqakdi9 9726
14:05:25,818 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1g6cybvqakdi9 9726
14:05:25,852 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE 14plps4rq06yt 7683
14:05:25,926 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE 203bvunibuxk 8672
14:05:26,000 INFO  [stdout] (ajp--192.168.1.150-9080-5) REMOVE 1r9iozlb7qu9r 2409
14:05:26,018 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1r9iozlb7qu9r 2409
14:05:26,074 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 1ppcfzih1b7n1 2650
14:05:26,089 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1ppcfzih1b7n1 2650
14:05:26,149 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 1txlmv2g46ejn 7653
14:05:26,165 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1txlmv2g46ejn 7653
14:05:26,223 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE 14htpvro4ua8b 6724
14:05:26,297 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT gko8x4cupkow 2930
14:05:26,312 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE gko8x4cupkow 2930
14:05:26,370 INFO  [stdout] (ajp--192.168.1.150-9080-5) UPDATE v1umqwkx1k66 2260
14:05:26,445 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT zgqo2m35w2rf 1036
14:05:26,462 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE zgqo2m35w2rf 1036
14:05:26,519 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 13wg0dr2yz95m 5299
14:05:26,573 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 13wg0dr2yz95m 5299
14:05:26,601 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT m0u74puq89vw 9140
14:05:26,668 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE 1o73cgsnhxe1l 7199
14:05:26,690 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE m0u74puq89vw 9140
14:05:26,742 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE g3gvziu30w7f 2402
14:05:26,815 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE zjf2pdu9snm1 1587
14:05:26,889 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE 615ovr9vnkzc 2066
14:05:26,964 INFO  [stdout] (ajp--192.168.1.150-9080-2) INSERT jpwd49sr1cly 5427
14:05:26,992 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE jpwd49sr1cly 5427
14:05:27,038 INFO  [stdout] (ajp--192.168.1.150-9080-2) INSERT 1s0qu81j9u4q 2307
14:05:27,057 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1s0qu81j9u4q 2307
14:05:27,111 INFO  [stdout] (ajp--192.168.1.150-9080-2) INSERT 1s0apr8p9juh4 1542
14:05:27,146 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1s0apr8p9juh4 1542
14:05:27,186 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE gjs31ymrin87 4821
14:05:27,260 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE 11vot9hvntfs8 35
14:05:27,334 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE 1xo7mg9v65stg 1049
14:05:27,408 INFO  [stdout] (ajp--192.168.1.150-9080-2) INSERT wktkiqe9pqns 4409
14:05:27,424 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE wktkiqe9pqns 4409
14:05:27,482 INFO  [stdout] (ajp--192.168.1.150-9080-2) INSERT tm5zdpk92har 7091
14:05:27,556 INFO  [stdout] (ajp--192.168.1.150-9080-5) INSERT 1bc5firf5fmpp 4603
14:05:27,581 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE tm5zdpk92har 7091
14:05:27,673 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE 7wamgve30owb 4823
14:05:27,678 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1bc5firf5fmpp 4603
14:05:27,705 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE gdphs99168dv 3373
14:05:27,780 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE 1g9af1sb4cg8a 8509
14:05:27,853 INFO  [stdout] (ajp--192.168.1.150-9080-2) UPDATE nz1m577xzqs0 9061
# LOGGING CLUSTER SERVER 2
14:03:01,204 INFO  [org.jboss.as.webservices] (ServerService Thread Pool -- 32) JBAS015537: Activating WebServices Extension
14:03:01,288 INFO  [org.jboss.as.security] (ServerService Thread Pool -- 36) JBAS013101: Activating Security Subsystem
14:03:01,312 INFO  [org.jboss.as.security] (MSC service thread 1-2) JBAS013100: Current PicketBox version=4.0.6.final
14:03:01,367 INFO  [org.jboss.as.osgi] (ServerService Thread Pool -- 41) JBAS011940: Activating OSGi Subsystem
14:03:01,398 INFO  [org.jboss.as.naming] (ServerService Thread Pool -- 42) JBAS011800: Activating Naming Subsystem
14:03:01,538 INFO  [org.jboss.as.naming] (MSC service thread 1-2) JBAS011802: Starting Naming Service
14:03:01,575 INFO  [org.jboss.as.mail.extension] (MSC service thread 1-2) JBAS015400: Bound mail session [java:jboss/mail/Default]
14:03:01,635 INFO  [org.jboss.as.clustering.jgroups] (ServerService Thread Pool -- 49) JBAS010260: Activating JGroups subsystem.
14:03:01,706 INFO  [org.jboss.as.jacorb] (ServerService Thread Pool -- 54) JBAS016300: Activating JacORB Subsystem
14:03:01,716 INFO  [org.jboss.as.clustering.infinispan] (ServerService Thread Pool -- 55) JBAS010280: Activating Infinispan subsystem.
14:03:01,809 INFO  [org.jboss.as.connector.subsystems.datasources] (ServerService Thread Pool -- 58) JBAS010403: Deploying JDBC-compliant driver class org.h2.Driver (version 1.3)
14:03:01,819 INFO  [org.jboss.as.configadmin] (ServerService Thread Pool -- 59) JBAS016200: Activating ConfigAdmin Subsystem
14:03:01,832 INFO  [org.jboss.ws.common.management.AbstractServerConfig] (MSC service thread 1-2) JBoss Web Services - Stack CXF Server 4.0.1.GA
14:03:02,005 INFO  [org.jboss.as.connector] (MSC service thread 1-4) JBAS010408: Starting JCA Subsystem (JBoss IronJacamar 1.0.7.Final)
14:03:02,190 INFO  [org.jboss.as.modcluster] (MSC service thread 1-2) JBAS011704: Mod_cluster uses default load balancer provider
14:03:02,253 INFO  [org.jboss.as.jaxr] (MSC service thread 1-1) Binding JAXR ConnectionFactory: java:jboss/jaxr/ConnectionFactory
14:03:02,340 INFO  [org.jboss.as.connector.subsystems.datasources] (ServerService Thread Pool -- 58) JBAS010403: Deploying JDBC-compliant driver class oracle.jdbc.OracleDriver (version 11.2)
14:03:02,366 INFO  [org.jboss.modcluster.ModClusterService] (MSC service thread 1-2) Initializing mod_cluster 1.2.0.Final
14:03:02,417 INFO  [org.apache.coyote.ajp.AjpAprProtocol] (MSC service thread 1-4) Starting Coyote AJP/1.3 on ajp-axis-into-ict.nl-192.168.1.150-9081
14:03:02,475 INFO  [org.apache.coyote.http11.Http11AprProtocol] (MSC service thread 1-3) Starting Coyote HTTP/1.1 on http-axis-into-ict.nl-192.168.1.150-8081
14:03:02,479 INFO  [org.jboss.modcluster.advertise.impl.AdvertiseListenerImpl] (MSC service thread 1-2) Listening to proxy advertisements on 224.0.1.105:23364
14:03:02,647 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-1) live server is starting with configuration HornetQ Configuration (clustered=false,backup=false,sharedStore=true,journalDirectory=/home/jboss/jboss-as-7.1.0.Final/domain/servers/cluster-server2/data/messagingjournal,bindingsDirectory=/home/jboss/jboss-as-7.1.0.Final/domain/servers/cluster-server2/data/messagingbindings,largeMessagesDirectory=/home/jboss/jboss-as-7.1.0.Final/domain/servers/cluster-server2/data/messaginglargemessages,pagingDirectory=/home/jboss/jboss-as-7.1.0.Final/domain/servers/cluster-server2/data/messagingpaging)
14:03:02,651 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-1) Waiting to obtain live lock
14:03:02,858 INFO  [org.infinispan.configuration.cache.EvictionConfigurationBuilder] (ServerService Thread Pool -- 55) ISPN000152: Passivation configured without an eviction policy being selected. Only manually evicted entities will be pasivated.
14:03:02,885 INFO  [org.hornetq.core.persistence.impl.journal.JournalStorageManager] (MSC service thread 1-1) Using AIO Journal
14:03:03,042 INFO  [org.infinispan.configuration.cache.EvictionConfigurationBuilder] (ServerService Thread Pool -- 55) ISPN000152: Passivation configured without an eviction policy being selected. Only manually evicted entities will be pasivated.
14:03:03,486 INFO  [org.jboss.as.jacorb] (MSC service thread 1-3) JBAS016330: CORBA ORB Service started
14:03:03,584 INFO  [org.hornetq.core.server.impl.AIOFileLockNodeManager] (MSC service thread 1-1) Waiting to obtain live lock
14:03:03,586 INFO  [org.hornetq.core.server.impl.AIOFileLockNodeManager] (MSC service thread 1-1) Live Server Obtained live lock
14:03:03,859 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-3) JBAS010400: Bound data source [java:jboss/datasources/ExampleDS]
14:03:03,943 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-4) JBAS010400: Bound data source [java:/jdbc/OracleDS]
14:03:04,191 INFO  [org.jboss.as.jacorb] (MSC service thread 1-3) JBAS016328: CORBA Naming Service started
14:03:04,825 INFO  [org.jboss.as.remoting] (MSC service thread 1-4) JBAS017100: Listening on axis-into-ict.nl/192.168.1.150:4448
14:03:05,139 INFO  [org.hornetq.core.remoting.impl.netty.NettyAcceptor] (MSC service thread 1-1) Started Netty Acceptor version 3.2.5.Final-a96d88c axis-into-ict.nl:5446 for CORE protocol
14:03:05,141 INFO  [org.hornetq.core.remoting.impl.netty.NettyAcceptor] (MSC service thread 1-1) Started Netty Acceptor version 3.2.5.Final-a96d88c axis-into-ict.nl:5456 for CORE protocol
14:03:05,142 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-1) Server is now live
14:03:05,143 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-1) HornetQ Server version 2.2.11.Final (HQ_2_2_11_FINAL_AS7, 122) [3f00f7a1-78e4-11e1-800d-000c2976c82d]) started
14:03:05,163 INFO  [org.jboss.as.messaging] (MSC service thread 1-1) JBAS011601: Bound messaging object to jndi name java:/ConnectionFactory
14:03:05,165 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-2) trying to deploy queue jms.topic.testTopic
14:03:05,203 INFO  [org.jboss.as.messaging] (MSC service thread 1-2) JBAS011601: Bound messaging object to jndi name java:/topic/test
14:03:05,210 INFO  [org.jboss.as.messaging] (MSC service thread 1-2) JBAS011601: Bound messaging object to jndi name java:jboss/exported/jms/topic/test
14:03:05,211 INFO  [org.jboss.as.messaging] (MSC service thread 1-4) JBAS011601: Bound messaging object to jndi name java:jboss/exported/jms/RemoteConnectionFactory
14:03:05,212 INFO  [org.jboss.as.messaging] (MSC service thread 1-4) JBAS011601: Bound messaging object to jndi name java:/RemoteConnectionFactory
14:03:05,214 INFO  [org.hornetq.core.server.impl.HornetQServerImpl] (MSC service thread 1-3) trying to deploy queue jms.queue.testQueue
14:03:05,224 INFO  [org.jboss.as.messaging] (MSC service thread 1-3) JBAS011601: Bound messaging object to jndi name java:jboss/exported/jms/queue/test
14:03:05,232 INFO  [org.jboss.as.messaging] (MSC service thread 1-3) JBAS011601: Bound messaging object to jndi name java:/queue/test
14:03:05,261 INFO  [org.jboss.as.deployment.connector] (MSC service thread 1-1) JBAS010406: Registered connection factory java:/JmsXA
14:03:05,270 INFO  [org.hornetq.ra.HornetQResourceAdapter] (MSC service thread 1-1) HornetQ resource adaptor started
14:03:05,271 INFO  [org.jboss.as.connector.services.ResourceAdapterActivatorService$ResourceAdapterActivator] (MSC service thread 1-1) IJ020002: Deployed: file://RaActivatorhornetq-ra
14:03:05,274 INFO  [org.jboss.as.deployment.connector] (MSC service thread 1-2) JBAS010401: Bound JCA ConnectionFactory [java:/JmsXA]
14:03:05,359 INFO  [org.jboss.as] (Controller Boot Thread) JBAS015874: JBoss AS 7.1.0.Final "Thunder" started in 7666ms - Started 169 of 292 services (121 services are passive or on-demand)
14:03:11,983 INFO  [org.jboss.modcluster.ModClusterService] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) Engine [jboss.web] will use jvmRoute: 4d87f106-10ff-342f-a6e6-eb2377d7c23f
14:04:34,835 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-3) JBAS015876: Starting deployment of "SpringHibernate.war"
14:04:35,550 INFO  [org.jboss.web] (MSC service thread 1-2) JBAS018210: Registering web context: /SpringHibernate
14:04:35,621 INFO  [org.jboss.as.server] (host-controller-connection-threads - 2) JBAS018559: Deployed "SpringHibernate.war"
14:05:16,923 INFO  [org.springframework.context.support.ClassPathXmlApplicationContext] (ajp--192.168.1.150-9081-8) Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@a58d300: startup date [Wed Aug 22 14:05:16 CEST 2012]; root of context hierarchy
14:05:16,960 INFO  [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] (ajp--192.168.1.150-9081-8) Loading XML bean definitions from class path resource [spring-config.xml]
14:05:17,216 INFO  [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer] (ajp--192.168.1.150-9081-8) Loading properties file from class path resource [spring.properties]
14:05:17,234 INFO  [org.springframework.beans.factory.support.DefaultListableBeanFactory] (ajp--192.168.1.150-9081-8) Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@164163e1: defining beans [company,sessionfactory,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,datasource,connectionfactory,destination,jmstemplate,org.springframework.jms.listener.DefaultMessageListenerContainer#0,companymdp,propertyConfigurer]; root of factory hierarchy
14:05:17,301 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp--192.168.1.150-9081-8) Using JTA UserTransaction: org.jboss.tm.usertx.client.ServerVMClientUserTransaction@575887db
14:05:17,302 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp--192.168.1.150-9081-8) Using JTA TransactionManager: com.arjuna.ats.jbossatx.jta.TransactionManagerDelegate@445aa997
14:05:17,303 INFO  [org.springframework.transaction.jta.JtaTransactionManager] (ajp--192.168.1.150-9081-8) Using JTA TransactionSynchronizationRegistry: com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple@1b1dd242
14:05:17,389 INFO  [org.hibernate.annotations.common.Version] (ajp--192.168.1.150-9081-8) HCANN000001: Hibernate Commons Annotations {4.0.1.Final}
14:05:17,394 INFO  [org.hibernate.Version] (ajp--192.168.1.150-9081-8) HHH000412: Hibernate Core {4.0.1.Final}
14:05:17,395 INFO  [org.hibernate.cfg.Environment] (ajp--192.168.1.150-9081-8) HHH000206: hibernate.properties not found
14:05:17,397 INFO  [org.hibernate.cfg.Environment] (ajp--192.168.1.150-9081-8) HHH000021: Bytecode provider name : javassist
14:05:17,435 WARN  [org.hibernate.internal.util.xml.DTDEntityResolver] (ajp--192.168.1.150-9081-8) HHH000223: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/. Use namespace http://www.hibernate.org/dtd/ instead. Refer to Hibernate 3.6 Migration Guide!
14:05:17,659 INFO  [org.hibernate.dialect.Dialect] (ajp--192.168.1.150-9081-8) HHH000400: Using dialect: org.hibernate.dialect.Oracle10gDialect
14:05:17,678 INFO  [org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory] (ajp--192.168.1.150-9081-8) HHH000397: Using ASTQueryTranslatorFactory
14:05:17,711 INFO  [org.hibernate.validator.util.Version] (ajp--192.168.1.150-9081-8) Hibernate Validator 4.2.0.Final
14:05:17,993 INFO  [org.springframework.context.support.DefaultLifecycleProcessor] (ajp--192.168.1.150-9081-8) Starting beans in phase 2147483647
14:05:18,212 INFO  [stdout] (ajp--192.168.1.150-9081-8) UPDATE 1nuxg993ownem 3052
14:05:21,115 INFO  [stdout] (ajp--192.168.1.150-9081-8) UPDATE afhvji2k8ft7 2716
14:05:21,185 INFO  [stdout] (ajp--192.168.1.150-9081-5) INSERT 1ihgf2p7aavvv 6429
14:05:21,328 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1ihgf2p7aavvv 6429
14:05:21,329 INFO  [stdout] (ajp--192.168.1.150-9081-3) UPDATE 1om511m6nzi22 4774
14:05:21,343 INFO  [stdout] (ajp--192.168.1.150-9081-4) INSERT 1hwkf2797ujf6 5149
14:05:21,404 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1hwkf2797ujf6 5149
14:05:21,441 INFO  [stdout] (ajp--192.168.1.150-9081-6) INSERT 1ezyhvfha3q2t 3836
14:05:21,478 INFO  [stdout] (ajp--192.168.1.150-9081-4) UPDATE 1ixbel89n7f5w 9298
14:05:21,502 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1ezyhvfha3q2t 3836
14:05:21,551 INFO  [stdout] (ajp--192.168.1.150-9081-6) INSERT 1us8n7k0bnqpo 5426
14:05:21,593 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1us8n7k0bnqpo 5426
14:05:21,627 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 1ppw7krne465v 6792
14:05:21,701 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 1prt2df94i5mk 2092
14:05:21,776 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 10gvhg82ztew9 2783
14:05:21,793 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 10gvhg82ztew9 2783
14:05:21,858 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 1bd9yo40vzizt 1911
14:05:21,923 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 5n9h8rwq7q60 1343
14:05:21,997 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 8m9k1pr28gg 5547
14:05:22,013 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 8m9k1pr28gg 5547
14:05:22,071 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 17r9ee4bt0yxs 3649
14:05:22,150 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 1gn2tjij0f1ob 1035
14:05:22,219 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT m6xox6axoz3b 3157
14:05:22,235 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE m6xox6axoz3b 3157
14:05:22,294 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 110r9484rvt73 294
14:05:22,310 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 110r9484rvt73 294
14:05:22,368 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 1c9c6tb2agswh 9932
14:05:22,407 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1c9c6tb2agswh 9932
14:05:22,444 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 50ipwt1zajdx 2131
14:05:22,515 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 29h8tcc65j3 4548
14:05:22,533 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 29h8tcc65j3 4548
14:05:22,594 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT bhunhawsm27p 1700
14:05:22,611 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE bhunhawsm27p 1700
14:05:22,664 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 9bh7fa74xnrm 1225
14:05:22,738 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 19f4hj421s3fe 5128
14:05:22,815 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT ydgfqj2u2aax 8844
14:05:22,833 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE ydgfqj2u2aax 8844
14:05:22,849 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT mmw7kqjojuyq 1966
14:05:22,865 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE mmw7kqjojuyq 1966
14:05:22,923 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE qpbhdyvgftko 9965
14:05:22,997 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT m22f1xogzs2w 5940
14:05:23,013 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE m22f1xogzs2w 5940
14:05:23,075 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE q9lquj1fxj4m 4504
14:05:23,147 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE belkm98whjwh 7385
14:05:23,222 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 1dq640hgxrqoe 496
14:05:23,239 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1dq640hgxrqoe 496
14:05:23,294 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 1pevcvw6wa91q 8567
14:05:23,323 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1pevcvw6wa91q 8567
14:05:23,370 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 15bm9suyux8ui 1530
14:05:23,389 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 15bm9suyux8ui 1530
14:05:23,443 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 1kmqno89copfp 7009
14:05:23,516 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 1l8beowesem93 8780
14:05:23,547 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1l8beowesem93 8780
14:05:23,595 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 1k9yrkaxqeizz 7066
14:05:23,665 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE p93n8ojg5gaf 8632
14:05:23,739 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 1v9ix94fvw3s2 5428
14:05:23,813 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT eo8kvhum40m3 4855
14:05:23,849 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE eo8kvhum40m3 4855
14:05:23,887 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT ehuvh8mnrdor 7519
14:05:23,901 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE ehuvh8mnrdor 7519
14:05:23,962 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 42395k914sap 9967
14:05:23,988 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 42395k914sap 9967
14:05:24,035 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT y3s6i0iy5bxc 2600
14:05:24,051 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE y3s6i0iy5bxc 2600
14:05:24,111 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 3us32d2krjvq 4008
14:05:24,186 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 9rg1q23jbt1h 5890
14:05:24,208 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 9rg1q23jbt1h 5890
14:05:24,332 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 1ayxc04tdei19 9978
14:05:24,348 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1ayxc04tdei19 9978
14:05:24,406 INFO  [stdout] (ajp--192.168.1.150-9081-7) REMOVE 1aczxa7rq66gc 7734
14:05:24,422 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1aczxa7rq66gc 7734
14:05:24,480 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 1qxbi4c03ptl3 2096
14:05:24,494 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1qxbi4c03ptl3 2096
14:05:24,554 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE k2zwhkup05z6 8428
14:05:24,633 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT as7552dnufu 899
14:05:24,648 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE as7552dnufu 899
14:05:24,703 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT l5zi29x6gxno 5344
14:05:24,717 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE l5zi29x6gxno 5344
14:05:24,777 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE r311dyu91dym 1859
14:05:24,852 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 1fxxn3gl91h8m 3280
14:05:24,925 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 1xqnw0zd807wd 2425
14:05:24,975 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1xqnw0zd807wd 2425
14:05:25,001 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 1md19po93vtqw 6630
14:05:25,073 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 2c9cplr913cz 1431
14:05:25,108 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 2c9cplr913cz 1431
14:05:25,147 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT v43yhet3xd1g 66
14:05:25,162 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE v43yhet3xd1g 66
14:05:25,221 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 1f7m1o552i1ap 5103
14:05:25,296 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 1vso63da2hxsz 4821
14:05:25,369 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT sz5f4p22ihxm 8460
14:05:25,418 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE sz5f4p22ihxm 8460
14:05:25,445 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 2a7fe1kbyn05 3485
14:05:25,496 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 2a7fe1kbyn05 3485
14:05:25,518 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT ydkzaajaai23 8793
14:05:25,585 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE ydkzaajaai23 8793
14:05:25,593 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 1nazvx44fsryy 2224
14:05:25,610 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1nazvx44fsryy 2224
14:05:25,667 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT ckpdo13cbu3v 8647
14:05:25,681 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE ckpdo13cbu3v 8647
14:05:25,740 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT bnydn2bxk8wd 1831
14:05:25,755 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE bnydn2bxk8wd 1831
14:05:25,815 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE fl1lk4bscdoj 7360
14:05:25,889 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE r8s5rxlisovh 3498
14:05:25,963 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 1o12rg3cdx2vk 1350
14:05:26,037 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 1gr04agkc8l6 4563
14:05:26,111 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 1c3ksedbtpaoq 3054
14:05:26,150 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1c3ksedbtpaoq 3054
14:05:26,185 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 17s438pq34yde 3952
14:05:26,219 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 17s438pq34yde 3952
14:05:26,259 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 14grcfgntxm7g 6624
14:05:26,274 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 14grcfgntxm7g 6624
14:05:26,333 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 9rlyy5ku91wv 257
14:05:26,348 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 9rlyy5ku91wv 257
14:05:26,407 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 5ek3d1123mwp 3383
14:05:26,451 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 5ek3d1123mwp 3383
14:05:26,481 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT xucmrjfo2tkr 3652
14:05:26,526 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE xucmrjfo2tkr 3652
14:05:26,556 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 13st8rbs16ek0 4776
14:05:26,586 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 13st8rbs16ek0 4776
14:05:26,631 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 21xvhp0ohbc0 6680
14:05:26,705 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT yyqn8d3edsvp 340
14:05:26,751 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE yyqn8d3edsvp 340
14:05:26,779 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 19qwovr0pstvu 3878
14:05:26,852 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 10lz3rhlhi1mn 8828
14:05:26,926 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 5m3i1gvcm0jx 4490
14:05:26,971 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 5m3i1gvcm0jx 4490
14:05:27,007 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 10x2dlavqagr7 1772
14:05:27,053 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 10x2dlavqagr7 1772
14:05:27,074 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 1irlznr87cp7v 6876
14:05:27,149 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT jh9pj68vmhla 7165
14:05:27,196 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE jh9pj68vmhla 7165
14:05:27,222 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 2eibuwgmnyai 1734
14:05:27,297 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE cmh5uq6jfdh1 1425
14:05:27,371 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 1by141cbe2jw2 3937
14:05:27,415 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1by141cbe2jw2 3937
14:05:27,446 INFO  [stdout] (ajp--192.168.1.150-9081-7) INSERT 1t1gansg3mryj 540
14:05:27,520 INFO  [stdout] (ajp--192.168.1.150-9081-6) INSERT b8uhwlgalst0 7532
14:05:27,544 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE b8uhwlgalst0 7532
14:05:27,584 INFO  [stdout] (org.springframework.jms.listener.DefaultMessageListenerContainer#0-1) RECEIVED OBJECT MESSAGE 1t1gansg3mryj 540
14:05:27,594 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 1ox069v1p4zue 7684
14:05:27,686 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 12obz6cvdizpk 4250
14:05:27,741 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE z7hc2gm1tko7 9967
14:05:27,819 INFO  [stdout] (ajp--192.168.1.150-9081-7) UPDATE 1sn0ranavpi7w 4442

Migration

Let us just deploy the application on WebLogic Server and see if we can get the Spring Hibernate application to work here as well. To this end, we create two shared libraries one for Spring 3.1.2 and one for Hibernate 4.1.2. The hibernate-4.1.war shared library has the following contents:

hibernate-4.1
	META-INF
		MANIFEST.MF
	WEB-INF
		lib
			antlr-2.7.7.jar
			dom4j-1.6.1.jar
			hibernate-commons-annotations-4.0.1.Final.jar
			hibernate-core-4.1.2.Final.jar
			hibernate-jpa-2.0-api-1.0.1.Final.jar
			javassist-3.15.0-GA.jar
			jboss-logging-3.1.0.GA.jar
			jboss-transaction-api_1.1_spec-1.0.0.Final.jar

in which the MANIFEST.MF contains:

Manifest-Version: 1.0
Created-By: 1.6.0_05 (BEA Systems, Inc.)
Extension-Name: hibernate
Specification-Title: Hibernate Library
Specification-Version: 4.1
Specification-Vendor: Middleware Magic
Implementation-Title: Hibernate Library
Implementation-Version: 4.1.2
Implementation-Vendor: Middleware Magic

The spring-3.1.war shared library has the following contents:

spring-3.1
	META-INF
		MANIFEST.MF
	WEB-INF
		lib
			aopalliance-1.0.jar
			cglib-2.2.2.jar
			commons-logging-1.0.4.jar
			org.springframework.aop-3.1.2.RELEASE.jar
			org.springframework.asm-3.1.2.RELEASE.jar
			org.springframework.beans-3.1.2.RELEASE.jar
			org.springframework.context-3.1.2.RELEASE.jar
			org.springframework.core-3.1.2.RELEASE.jar
			org.springframework.expression-3.1.2.RELEASE.jar
			org.springframework.jdbc-3.1.2.RELEASE.jar
			org.springframework.jms-3.1.2.RELEASE.jar
			org.springframework.orm-3.1.2.RELEASE.jar
			org.springframework.transaction-3.1.2.RELEASE.jar
			org.springframework.web-3.1.2.RELEASE.jar

in which the MANIFEST.MF contains:

Manifest-Version: 1.0
Created-By: 1.6.0_05 (BEA Systems, Inc.)
Extension-Name: spring
Specification-Title: Spring Library
Specification-Version: 3.1
Specification-Vendor: Middleware Magic
Implementation-Title: Spring Library
Implementation-Version: 3.1.2
Implementation-Vendor: Middleware Magic

We deploy the shared libraries to the WebLogic environment that is set-up as in the post Deploy WebLogic12c to Multiple Machines. The used Spring configuration looks as follows:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
    <bean id="company" class="model.logic.CompanyBean">
        <property name="sessionFactory" ref="sessionfactory"/>
        <property name="jmsTemplate" ref="jmstemplate"/>
    </bean>
	<!-- Hibernate SessionFactory config -->
    <bean id="sessionfactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="datasource"/>
        <property name="jtaTransactionManager" ref="transactionManager"/>
        <property name="mappingResources">
            <list>
                <value>model/entities/person.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.current_session_context_class">${hibernate.current_session_context_class}</prop>
                <prop key="hibernate.listeners.envers.autoRegister">${hibernate.listeners.envers.autoRegister}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
            </props>
        </property>
    </bean>
	<!-- Transaction config -->
	<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
	<tx:annotation-driven transaction-manager="transactionManager"/>
	<!-- Resource look-ups -->
    <jee:jndi-lookup id="datasource" jndi-name="jdbc/exampleDS" resource-ref="false"/>
    <jee:jndi-lookup id="connectionfactory" jndi-name="jms/ConnectionFactory" resource-ref="false"/>
	<jee:jndi-lookup id="destination" jndi-name="jms/CompanyQueue" resource-ref="false"/>
    <!-- JMS config -->
	<bean id="jmstemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionfactory"/>
        <property name="defaultDestination" ref="destination"/>
    </bean>
    <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionfactory"/>
        <property name="destination" ref="destination"/>
        <property name="transactionManager" ref="transactionManager"/>
        <property name="messageListener" ref="companymdp"/>
    </bean>
    <bean id="companymdp" class="model.logic.CompanyMDP"/>
	<!-- Extra -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:spring.properties</value>
            </list>
        </property>
    </bean>
</beans>

Note that the only things that are changed are the JNDI-names of the used resources (data source, connection factory and destination). In order to deploy the application to WebLogic we can use the following directory structure

/springhibernate
	/app
		SpringHibernate.war
	/plan
		/WEB-INF
			weblogic.xml
		plan.xml

in which weblogic.xml has the following contents

<weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd">
	<container-descriptor>
		<prefer-application-packages>
			<package-name>antlr.*</package-name>
		</prefer-application-packages>
	</container-descriptor>
	<library-ref>
		<library-name>hibernate</library-name>
		<specification-version>4.1</specification-version>
		<implementation-version>4.1.2</implementation-version>
		<exact-match>true</exact-match>
	</library-ref>
	<library-ref>
		<library-name>spring</library-name>
		<specification-version>3.1</specification-version>
		<implementation-version>3.1.2</implementation-version>
		<exact-match>true</exact-match>
	</library-ref>
</weblogic-web-app>

When the application is deployed and the testservlet is accessed the following is observed in the logging

# LOGGING CLUSTER-SERVER1
Aug 17, 2012 11:17:18 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1e3741a5: startup date [Fri Aug 17 11:17:18 CEST 2012]; root of context hierarchy
Aug 17, 2012 11:17:18 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring-config.xml]
Aug 17, 2012 11:17:18 AM org.springframework.core.io.support.PropertiesLoaderSupport loadProperties
INFO: Loading properties file from class path resource [spring.properties]
Aug 17, 2012 11:17:18 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1e57db48: defining beans [company,sessionfactory,datasource,propertyConfigurer,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,connectionfactory,destination,jmstemplate,org.springframework.jms.listener.DefaultMessageListenerContainer#0,companymdp]; root of factory hierarchy
Aug 17, 2012 11:17:18 AM org.springframework.transaction.jta.JtaTransactionManager checkUserTransactionAndTransactionManager
INFO: Using JTA UserTransaction: ClientTM[cluster-server1+axis-into-ict.nl:9001+base_domain+t3+]
Aug 17, 2012 11:17:18 AM org.springframework.transaction.jta.JtaTransactionManager checkUserTransactionAndTransactionManager
INFO: Using JTA TransactionManager: ClientTM[cluster-server1+axis-into-ict.nl:9001+base_domain+t3+]
Aug 17, 2012 11:17:18 AM org.springframework.transaction.jta.JtaTransactionManager initTransactionSynchronizationRegistry
INFO: Using JTA TransactionSynchronizationRegistry: ClientTM[cluster-server1+axis-into-ict.nl:9001+base_domain+t3+]
Aug 17, 2012 11:17:19 AM org.hibernate.annotations.common.Version <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.1.Final}
Aug 17, 2012 11:17:19 AM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.1.2.Final}
Aug 17, 2012 11:17:19 AM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
Aug 17, 2012 11:17:19 AM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
Aug 17, 2012 11:17:19 AM org.hibernate.internal.util.xml.DTDEntityResolver resolveEntity
WARN: HHH000223: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/. Use namespace http://www.hibernate.org/dtd/ instead. Refer to Hibernate 3.6 Migration Guide!
Aug 17, 2012 11:17:19 AM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.Oracle10gDialect
Aug 17, 2012 11:17:19 AM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
Aug 17, 2012 11:17:20 AM org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup start
INFO: Starting beans in phase 2147483647
INSERT 1vfaxqqm2868k 9170
RECEIVED OBJECT MESSAGE 1vfaxqqm2868k 9170
INSERT 1azwiw7lwh4y7 6205
RECEIVED OBJECT MESSAGE 1azwiw7lwh4y7 6205
UPDATE 1t4a3l9tlt0i1 7843
UPDATE 1gpie3s1fmk7a 5058
UPDATE wgiimvyfwc8i 5756
INSERT 1tmgsmdsi2sbh 435
RECEIVED OBJECT MESSAGE 1tmgsmdsi2sbh 435
UPDATE 1mqtq9gwil0py 8978
INSERT ts5nfho8b4wb 3167
RECEIVED OBJECT MESSAGE ts5nfho8b4wb 3167
INSERT j878nzzqf3b3 3553
RECEIVED OBJECT MESSAGE j878nzzqf3b3 3553
INSERT 1upuhpirvr0a7 938
RECEIVED OBJECT MESSAGE 1upuhpirvr0a7 938
UPDATE mgt58gj3d61n 3538
INSERT 1q5smfr3dh6df 2715
RECEIVED OBJECT MESSAGE 1q5smfr3dh6df 2715
UPDATE 1r3jwyj2g5x5m 6113
UPDATE 1d6cpm9lavqwg 1972
INSERT vxc1h63kfy2w 1496
RECEIVED OBJECT MESSAGE vxc1h63kfy2w 1496
INSERT 55otw4aj7n7u 3826
RECEIVED OBJECT MESSAGE 55otw4aj7n7u 3826
INSERT 1dl36wovta1vf 8045
RECEIVED OBJECT MESSAGE 1dl36wovta1vf 8045
INSERT p1693zg2q0bl 4673
RECEIVED OBJECT MESSAGE p1693zg2q0bl 4673
INSERT 1e6c1ssik0esu 8536
RECEIVED OBJECT MESSAGE 1e6c1ssik0esu 8536
INSERT w7hlqytbosrt 2874
RECEIVED OBJECT MESSAGE w7hlqytbosrt 2874
UPDATE 152p5lvqwxco8 9516
INSERT byh8hu448t7w 8913
RECEIVED OBJECT MESSAGE byh8hu448t7w 8913
INSERT 1dajek4kv7xgb 8368
RECEIVED OBJECT MESSAGE 1dajek4kv7xgb 8368
INSERT ju0rs6v1k0dv 6421
RECEIVED OBJECT MESSAGE ju0rs6v1k0dv 6421
UPDATE 107qwp5m3bh6u 4167
INSERT uewom3s9awr0 4933
RECEIVED OBJECT MESSAGE uewom3s9awr0 4933
INSERT 1gejfty8uqly1 9279
RECEIVED OBJECT MESSAGE 1gejfty8uqly1 9279
INSERT ixpxzvpr08ww 5428
RECEIVED OBJECT MESSAGE ixpxzvpr08ww 5428
INSERT 17qi3yaxwtrxu 7411
RECEIVED OBJECT MESSAGE 17qi3yaxwtrxu 7411
UPDATE 7fgzuwkcz48e 5716
INSERT 1tbtnsilprbmm 8680
RECEIVED OBJECT MESSAGE 1tbtnsilprbmm 8680
UPDATE 1b2b771wi8waz 6832
INSERT 14v47vzyr5egt 564
RECEIVED OBJECT MESSAGE 14v47vzyr5egt 564
INSERT v30iv4nv8g5n 4052
RECEIVED OBJECT MESSAGE v30iv4nv8g5n 4052
UPDATE 1f2rqzn03y5qq 7750
REMOVE 1ibtlrunczhdk 4166
REMOVE 19fzxc64sngs1 5131
INSERT 981c8ahs90go 6356
RECEIVED OBJECT MESSAGE 1ibtlrunczhdk 4166
RECEIVED OBJECT MESSAGE 981c8ahs90go 6356
RECEIVED OBJECT MESSAGE 19fzxc64sngs1 5131
INSERT 1dm92l3kuloyc 3669
RECEIVED OBJECT MESSAGE 1dm92l3kuloyc 3669
UPDATE 3dtym6dsmm8j 6477
UPDATE jm5v2s8kq5cn 436
UPDATE 1aa1z7okdo09k 8246
INSERT jjnultqc90f4 9607
RECEIVED OBJECT MESSAGE jjnultqc90f4 9607
INSERT 1mmixox5tpnnn 3279
RECEIVED OBJECT MESSAGE 1mmixox5tpnnn 3279
INSERT 1227bi0v86b3t 4022
RECEIVED OBJECT MESSAGE 1227bi0v86b3t 4022
UPDATE stvbc1ya5lc2 8047
UPDATE 1xntj3pwd7p9x 258
UPDATE 1k6r3ryeo8ulm 6901
UPDATE b2e526chsv6o 2934
INSERT 1q0axu96bm6lg 7173
RECEIVED OBJECT MESSAGE 1q0axu96bm6lg 7173
INSERT sigdxvz05hsi 3065
RECEIVED OBJECT MESSAGE sigdxvz05hsi 3065
INSERT 1hgbown1i5fc9 6686
RECEIVED OBJECT MESSAGE 1hgbown1i5fc9 6686
UPDATE 9s7hmdtntgkd 4601
UPDATE 17ce0wl4ealwc 2423
UPDATE 1a96qcppjpe5f 7212
UPDATE 152pp0q3zk8zg 4671
INSERT tdlhx4yk0pmg 9733
RECEIVED OBJECT MESSAGE tdlhx4yk0pmg 9733
UPDATE 622um5vc14mq 7765
INSERT 1lsx0iiup6gg5 6041
RECEIVED OBJECT MESSAGE 1lsx0iiup6gg5 6041
UPDATE 16ekljbz9e387 4309
UPDATE 1cezkqse6hvd0 3349
UPDATE 1a6olflotven8 1087
INSERT 1au7gq4p6mv8c 3261
RECEIVED OBJECT MESSAGE 1au7gq4p6mv8c 3261
INSERT 1em7bsp3g29w 2566
RECEIVED OBJECT MESSAGE 1em7bsp3g29w 2566
INSERT 1a4mkxcpjug71 6167
RECEIVED OBJECT MESSAGE 1a4mkxcpjug71 6167
UPDATE pmw4v5xst33l 5002
UPDATE 1mpp7mfpl5kru 682
UPDATE 10z3im4emd96i 4022
UPDATE 1jxworov8e1z9 9844
INSERT 1sedtpmbhtquc 270
RECEIVED OBJECT MESSAGE 1sedtpmbhtquc 270
UPDATE lwesgdzgwpl0 8422
UPDATE gvjyxm2c7jd0 5366
INSERT moiepveyd9xt 9931
RECEIVED OBJECT MESSAGE moiepveyd9xt 9931
INSERT a8kfudlzxcxy 6156
RECEIVED OBJECT MESSAGE a8kfudlzxcxy 6156
UPDATE o0hx0zv9qgzg 3469
INSERT ugs4gnhafozq 6680
RECEIVED OBJECT MESSAGE ugs4gnhafozq 6680
INSERT sdheu51y4yfx 8489
RECEIVED OBJECT MESSAGE sdheu51y4yfx 8489
UPDATE sq6j7i0baitp 6699
INSERT v2ojrjfekv9k 4533
RECEIVED OBJECT MESSAGE v2ojrjfekv9k 4533
UPDATE 10wfve0yjl4k4 4589
INSERT uqwxetfuogwt 9849
RECEIVED OBJECT MESSAGE uqwxetfuogwt 9849
UPDATE 1ush98l72a9d3 8258
UPDATE owyg8kl65g8j 4156
INSERT pb8v2gufr6rh 6497
RECEIVED OBJECT MESSAGE pb8v2gufr6rh 6497
INSERT dmfq7qiueu7x 9955
RECEIVED OBJECT MESSAGE dmfq7qiueu7x 9955
INSERT 13ke7pnvs9ylu 7792
RECEIVED OBJECT MESSAGE 13ke7pnvs9ylu 7792
INSERT y7kbegscmisj 896
RECEIVED OBJECT MESSAGE y7kbegscmisj 896
UPDATE 2iwm9v61fvhy 749
INSERT bdmcdk1ogf9l 6628
RECEIVED OBJECT MESSAGE bdmcdk1ogf9l 6628
INSERT 18bysp3l4gb0f 6056
RECEIVED OBJECT MESSAGE 18bysp3l4gb0f 6056
UPDATE 16hr14gvrsh1k 2122
UPDATE hyp4ojojxdes 8218
UPDATE 1khy3p4q9dclk 747
UPDATE 1uzuvg1xslcky 9561
UPDATE 1kgdpavy2chez 519
INSERT 1mox60j02zh85 9798
RECEIVED OBJECT MESSAGE 1mox60j02zh85 9798
INSERT ci128g9jo27u 7739
RECEIVED OBJECT MESSAGE ci128g9jo27u 7739
INSERT 6j5syb4xpota 9066
RECEIVED OBJECT MESSAGE 6j5syb4xpota 9066
UPDATE 652v8hhke5ai 4884
UPDATE 1u1dzud98psop 2480
UPDATE q6ci13nicvri 9825
INSERT 1n81wvaep5nr6 6212
RECEIVED OBJECT MESSAGE 1n81wvaep5nr6 6212
INSERT 18ncq6m6s1acl 3285
RECEIVED OBJECT MESSAGE 18ncq6m6s1acl 3285
INSERT zjtnfrh2ajsj 3407
RECEIVED OBJECT MESSAGE zjtnfrh2ajsj 3407
UPDATE q5ug6q1daqpn 6675
INSERT uzaeixyt6g0l 610
RECEIVED OBJECT MESSAGE uzaeixyt6g0l 610
INSERT rpftez66w9rr 1695
RECEIVED OBJECT MESSAGE rpftez66w9rr 1695
UPDATE 135a8m7uhk006 4194
UPDATE 14exorxy3klbg 5424
UPDATE 14r1nopyggixk 7215
UPDATE 1izhgww1gazcn 5707
UPDATE gz1k3p3nyzcz 30
UPDATE fnf7ggv9gy8s 7314
UPDATE 2ql8f9rupz8g 1206
UPDATE 7ylaxoxi9uua 4279
INSERT x5wphn4pz0xf 7045
RECEIVED OBJECT MESSAGE x5wphn4pz0xf 7045
UPDATE b8x13s890p7v 3471
INSERT ij7897v2tqp2 8531
RECEIVED OBJECT MESSAGE ij7897v2tqp2 8531
UPDATE 1ir4dulll98sj 7765
INSERT hwiqxp6cx32v 2775
RECEIVED OBJECT MESSAGE hwiqxp6cx32v 2775
INSERT 19lblxbbkdoi0 7419
RECEIVED OBJECT MESSAGE 19lblxbbkdoi0 7419
INSERT 1dgxsd9fcwthk 6299
RECEIVED OBJECT MESSAGE 1dgxsd9fcwthk 6299
UPDATE 17owe7epcdanl 7480
UPDATE qvzncb916e1l 6856
INSERT 1c5pamjalavz0 6374
RECEIVED OBJECT MESSAGE 1c5pamjalavz0 6374
INSERT 1xndfh1zhsm8t 7993
RECEIVED OBJECT MESSAGE 1xndfh1zhsm8t 7993
INSERT 1kz8donqnnc8g 2967
RECEIVED OBJECT MESSAGE 1kz8donqnnc8g 2967
INSERT 19qq0303net89 1906
RECEIVED OBJECT MESSAGE 19qq0303net89 1906
INSERT sax47077f9ka 3016
RECEIVED OBJECT MESSAGE sax47077f9ka 3016
INSERT pufs4n4rhr1e 7255
RECEIVED OBJECT MESSAGE pufs4n4rhr1e 7255
INSERT 1e5kf8rlv0kav 5159
RECEIVED OBJECT MESSAGE 1e5kf8rlv0kav 5159
INSERT 1ulnvxkxowbly 7415
RECEIVED OBJECT MESSAGE 1ulnvxkxowbly 7415
UPDATE t9edlkta9x06 7882
UPDATE 1pkra952k87nb 2277
INSERT 1v4x4t69qoyvv 1948
RECEIVED OBJECT MESSAGE 1v4x4t69qoyvv 1948
INSERT ynlrxbwg2o86 9056
RECEIVED OBJECT MESSAGE ynlrxbwg2o86 9056
INSERT 1pjurxwpfoafo 2735
RECEIVED OBJECT MESSAGE 1pjurxwpfoafo 2735
UPDATE sxec5z2fdc8t 9386
INSERT 1po7ankt6q1e6 1401
RECEIVED OBJECT MESSAGE 1po7ankt6q1e6 1401
UPDATE 10wjk2jzd5rgb 1541
UPDATE 1rs2vq5yy7603 4562
INSERT 12l3q5i8xcyem 6099
RECEIVED OBJECT MESSAGE 12l3q5i8xcyem 6099
INSERT 105ia9hr5xg3t 4083
RECEIVED OBJECT MESSAGE 105ia9hr5xg3t 4083
INSERT naup4tcu7c2w 9001
RECEIVED OBJECT MESSAGE naup4tcu7c2w 9001
INSERT r97pmgdg7z4y 4698
RECEIVED OBJECT MESSAGE r97pmgdg7z4y 4698
INSERT 11bba4337czby 444
RECEIVED OBJECT MESSAGE 11bba4337czby 444
INSERT lcodtofso3fy 3621
RECEIVED OBJECT MESSAGE lcodtofso3fy 3621
INSERT o2l983w9jov8 8912
RECEIVED OBJECT MESSAGE o2l983w9jov8 8912
INSERT 1urnou35ulywu 697
RECEIVED OBJECT MESSAGE 1urnou35ulywu 697
INSERT 1lvbw429diy7v 9018
RECEIVED OBJECT MESSAGE 1lvbw429diy7v 9018
INSERT 1p4pa3tntgroo 2444
RECEIVED OBJECT MESSAGE 1p4pa3tntgroo 2444
INSERT qxiiwynhc3gj 9248
RECEIVED OBJECT MESSAGE qxiiwynhc3gj 9248
# LOGGING CLUSTER-SERVER2
Aug 17, 2012 11:25:34 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1e701a84: startup date [Fri Aug 17 11:25:34 CEST 2012]; root of context hierarchy
Aug 17, 2012 11:25:35 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring-config.xml]
Aug 17, 2012 11:25:35 AM org.springframework.core.io.support.PropertiesLoaderSupport loadProperties
INFO: Loading properties file from class path resource [spring.properties]
Aug 17, 2012 11:25:35 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1e9c800e: defining beans [company,sessionfactory,datasource,propertyConfigurer,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,connectionfactory,destination,jmstemplate,org.springframework.jms.listener.DefaultMessageListenerContainer#0,companymdp]; root of factory hierarchy
Aug 17, 2012 11:25:35 AM org.springframework.transaction.jta.JtaTransactionManager checkUserTransactionAndTransactionManager
INFO: Using JTA UserTransaction: ClientTM[cluster-server2+axis-into-ict.nl:9002+base_domain+t3+]
Aug 17, 2012 11:25:35 AM org.springframework.transaction.jta.JtaTransactionManager checkUserTransactionAndTransactionManager
INFO: Using JTA TransactionManager: ClientTM[cluster-server2+axis-into-ict.nl:9002+base_domain+t3+]
Aug 17, 2012 11:25:35 AM org.springframework.transaction.jta.JtaTransactionManager initTransactionSynchronizationRegistry
INFO: Using JTA TransactionSynchronizationRegistry: ClientTM[cluster-server2+axis-into-ict.nl:9002+base_domain+t3+]
Aug 17, 2012 11:25:35 AM org.hibernate.annotations.common.Version <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.1.Final}
Aug 17, 2012 11:25:35 AM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.1.2.Final}
Aug 17, 2012 11:25:35 AM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
Aug 17, 2012 11:25:35 AM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
Aug 17, 2012 11:25:36 AM org.hibernate.internal.util.xml.DTDEntityResolver resolveEntity
WARN: HHH000223: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/. Use namespace http://www.hibernate.org/dtd/ instead. Refer to Hibernate 3.6 Migration Guide!
Aug 17, 2012 11:25:36 AM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.Oracle10gDialect
Aug 17, 2012 11:25:36 AM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
Aug 17, 2012 11:25:37 AM org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup start
INFO: Starting beans in phase 2147483647
INSERT 1ro7iaej9wd9k 8795
RECEIVED OBJECT MESSAGE 1ro7iaej9wd9k 8795
INSERT 1b1fcai34faga 6314
RECEIVED OBJECT MESSAGE 1b1fcai34faga 6314
INSERT 1v57ryimse5uf 9755
RECEIVED OBJECT MESSAGE 1v57ryimse5uf 9755
INSERT yx01xew3z2jh 9354
RECEIVED OBJECT MESSAGE yx01xew3z2jh 9354
UPDATE um8jioyfz2xw 3576
UPDATE fzzhd0wiga1j 5555
UPDATE g2yjl64y5r26 9223
UPDATE 1ajjz2xwnb0xy 6102
INSERT sc8lrc1ltn1c 3679
RECEIVED OBJECT MESSAGE sc8lrc1ltn1c 3679
UPDATE 19g20kvci9lgc 3349
INSERT yekowaz2yvvv 2135
RECEIVED OBJECT MESSAGE yekowaz2yvvv 2135
UPDATE hgoeapqkrf3h 9331
INSERT qoioytyju0pd 8055
RECEIVED OBJECT MESSAGE qoioytyju0pd 8055
UPDATE q9kkzncyf9vg 5423
INSERT 1e0hjp4authf2 7252
RECEIVED OBJECT MESSAGE 1e0hjp4authf2 7252
INSERT kfuv64fpg5xh 9006
RECEIVED OBJECT MESSAGE kfuv64fpg5xh 9006
UPDATE 1bzhy6v1trxil 2834
INSERT 3jeohjlsc4ai 3093
RECEIVED OBJECT MESSAGE 3jeohjlsc4ai 3093
INSERT dlbnur9etkbu 9469
RECEIVED OBJECT MESSAGE dlbnur9etkbu 9469
UPDATE 1p02mjgb66m5c 8668
UPDATE 1nkdo6q2dok30 6031
INSERT 1memxxtvl9d7j 8365
RECEIVED OBJECT MESSAGE 1memxxtvl9d7j 8365
INSERT 18qq5qqnowk38 4747
RECEIVED OBJECT MESSAGE 18qq5qqnowk38 4747
INSERT ojxr6mn4bkpf 4212
RECEIVED OBJECT MESSAGE ojxr6mn4bkpf 4212
INSERT 1s4hpfjw4uckk 8261
RECEIVED OBJECT MESSAGE 1s4hpfjw4uckk 8261
UPDATE a7267e4nojm5 7415
UPDATE 121eduf2de5o7 1629
INSERT 1jp76tnlkkk23 5448
RECEIVED OBJECT MESSAGE 1jp76tnlkkk23 5448
INSERT b3cvx730ikth 129
RECEIVED OBJECT MESSAGE b3cvx730ikth 129
UPDATE 11pwub752h6e4 4900
INSERT 1rra35pu4kx34 5472
RECEIVED OBJECT MESSAGE 1rra35pu4kx34 5472
UPDATE 1s0zsfne0divn 4096
UPDATE 1rtoy57gl7bhu 2614
UPDATE ezzxkiss0quj 3927
UPDATE 1l9zzie9sjjwx 8543
INSERT 1hufcx719vzm1 3106
RECEIVED OBJECT MESSAGE 1hufcx719vzm1 3106
UPDATE 1wifye5nhv9fh 8054
INSERT m2e4uladi9g0 5162
RECEIVED OBJECT MESSAGE m2e4uladi9g0 5162
INSERT arag8dj5j6k8 9491
RECEIVED OBJECT MESSAGE arag8dj5j6k8 9491
UPDATE vchq9193eelj 4236
INSERT r2lu5002hm8q 3371
RECEIVED OBJECT MESSAGE r2lu5002hm8q 3371
INSERT ah5ivj9eb08g 6552
RECEIVED OBJECT MESSAGE ah5ivj9eb08g 6552
INSERT 9wbnmdm841qe 5687
RECEIVED OBJECT MESSAGE 9wbnmdm841qe 5687
INSERT m7dk38en2pa6 2771
RECEIVED OBJECT MESSAGE m7dk38en2pa6 2771
INSERT 2ccmfrlth7qi 7890
RECEIVED OBJECT MESSAGE 2ccmfrlth7qi 7890
INSERT 1j4u6kowyig5h 7865
RECEIVED OBJECT MESSAGE 1j4u6kowyig5h 7865
UPDATE 71ter5vkj56o 6106
INSERT 9o7qpmcbl4vh 1349
RECEIVED OBJECT MESSAGE 9o7qpmcbl4vh 1349
INSERT lmr4oqlu0o0o 5685
RECEIVED OBJECT MESSAGE lmr4oqlu0o0o 5685
INSERT y2du188lqyjy 1659
RECEIVED OBJECT MESSAGE y2du188lqyjy 1659
INSERT ud58jd9xkmir 4338
RECEIVED OBJECT MESSAGE ud58jd9xkmir 4338
INSERT 33sskk07r3j 2585
RECEIVED OBJECT MESSAGE 33sskk07r3j 2585
INSERT 1o3gde8i54tgt 1874
RECEIVED OBJECT MESSAGE 1o3gde8i54tgt 1874
INSERT i2ixrboywlv1 4780
RECEIVED OBJECT MESSAGE i2ixrboywlv1 4780
INSERT zwtyym43rr61 9273
RECEIVED OBJECT MESSAGE zwtyym43rr61 9273
INSERT 1im8h986ltsjb 4391
RECEIVED OBJECT MESSAGE 1im8h986ltsjb 4391
INSERT 12bcoiykhyxbz 2045
RECEIVED OBJECT MESSAGE 12bcoiykhyxbz 2045
INSERT 344m66wfi4pj 2932
RECEIVED OBJECT MESSAGE 344m66wfi4pj 2932
INSERT avu4p8rk1u49 1110
RECEIVED OBJECT MESSAGE avu4p8rk1u49 1110
INSERT 1qjb6odryerif 1602
RECEIVED OBJECT MESSAGE 1qjb6odryerif 1602
UPDATE sd8x343td04w 8207
UPDATE 1nkz2pyuxq6uf 8336
INSERT 1wd44tnl8sb21 3082
RECEIVED OBJECT MESSAGE 1wd44tnl8sb21 3082
INSERT 2osxfuuxdxbm 6578
RECEIVED OBJECT MESSAGE 2osxfuuxdxbm 6578
UPDATE 1siosbc26v8pk 3497
INSERT 136pfbsg1r4pm 6778
RECEIVED OBJECT MESSAGE 136pfbsg1r4pm 6778
INSERT 1hbb0a41y2s2v 6981
RECEIVED OBJECT MESSAGE 1hbb0a41y2s2v 6981
INSERT fqxegdpt6rl4 9823
RECEIVED OBJECT MESSAGE fqxegdpt6rl4 9823
REMOVE z66prw2lb7bp 1849
RECEIVED OBJECT MESSAGE z66prw2lb7bp 1849
INSERT 11rh97d29fhky 9445
RECEIVED OBJECT MESSAGE 11rh97d29fhky 9445
UPDATE ebh10c5v33z1 8965
UPDATE 1vd660sbipcp1 8809
UPDATE 15xnralb7gz9s 9511
INSERT 1kd8n3a1hs1e1 9622
RECEIVED OBJECT MESSAGE 1kd8n3a1hs1e1 9622
INSERT 1lrqknnl2wa9b 4794
RECEIVED OBJECT MESSAGE 1lrqknnl2wa9b 4794
INSERT 1sihm871ppxgs 5251
RECEIVED OBJECT MESSAGE 1sihm871ppxgs 5251
UPDATE 1hl9r1c3jtsww 7388
INSERT 1ktajkpo6zkrt 5676
RECEIVED OBJECT MESSAGE 1ktajkpo6zkrt 5676
UPDATE 2dja2aq45ctz 3865
INSERT 161mpey6d6vr5 4319
RECEIVED OBJECT MESSAGE 161mpey6d6vr5 4319
UPDATE 1cb45pn2a4avu 4032
UPDATE s0lllla2u71m 976
INSERT 5upsxkqis7yg 9610
RECEIVED OBJECT MESSAGE 5upsxkqis7yg 9610
UPDATE 1nz3rzwkpow1r 7827
INSERT 13vklojl41kiz 2462
RECEIVED OBJECT MESSAGE 13vklojl41kiz 2462
INSERT zdtjhvacufbe 4345
RECEIVED OBJECT MESSAGE zdtjhvacufbe 4345
UPDATE s7wc62ybsumu 1280
INSERT 4pbi0tkgevwx 8057
RECEIVED OBJECT MESSAGE 4pbi0tkgevwx 8057
INSERT 6ip3sgwf3g3v 5447
RECEIVED OBJECT MESSAGE 6ip3sgwf3g3v 5447
INSERT 2rsxw9lvikhb 5606
RECEIVED OBJECT MESSAGE 2rsxw9lvikhb 5606
INSERT ubllgdw263e 5556
RECEIVED OBJECT MESSAGE ubllgdw263e 5556
INSERT 1recoqmjit876 9174
RECEIVED OBJECT MESSAGE 1recoqmjit876 9174
INSERT sor1hnjar6c2 5791
RECEIVED OBJECT MESSAGE sor1hnjar6c2 5791
INSERT 1d7r2ebnidhwx 2335
RECEIVED OBJECT MESSAGE 1d7r2ebnidhwx 2335
INSERT 1rtu3pc4ds3t0 7070
RECEIVED OBJECT MESSAGE 1rtu3pc4ds3t0 7070
UPDATE 1s79t8kafadq1 8465
UPDATE ax93q52uqnsk 1767
REMOVE e6n7hkwvo8yp 4487
RECEIVED OBJECT MESSAGE e6n7hkwvo8yp 4487
INSERT 1j6hs0edfxrkf 8433
RECEIVED OBJECT MESSAGE 1j6hs0edfxrkf 8433
INSERT 1lcd1uj5ikznc 7508
RECEIVED OBJECT MESSAGE 1lcd1uj5ikznc 7508
UPDATE sedm4wcjn1b 8343
UPDATE 1afyqhqvum90o 9944
INSERT 1v1r9p1dqm52t 210
RECEIVED OBJECT MESSAGE 1v1r9p1dqm52t 210
INSERT sg0hnmqe4dem 1375
RECEIVED OBJECT MESSAGE sg0hnmqe4dem 1375
UPDATE 75t1sh43ixpo 3927
UPDATE vg47h8u8d22f 6993
UPDATE fck5afipv4pa 5141
UPDATE 1cyykiwoedg49 8312
INSERT f10y81rg9yml 6747
RECEIVED OBJECT MESSAGE f10y81rg9yml 6747
INSERT 7l3f1g1mee1m 1420
RECEIVED OBJECT MESSAGE 7l3f1g1mee1m 1420
INSERT m28pdjg9x95g 8483
RECEIVED OBJECT MESSAGE m28pdjg9x95g 8483
INSERT 1j8xcvo5xnpjb 7360
RECEIVED OBJECT MESSAGE 1j8xcvo5xnpjb 7360
UPDATE 1sew10cgbiejp 3257
UPDATE 16hhdy988j64o 6329
UPDATE qzsxk5twh1de 5195
UPDATE 1agu0r1l7510z 431
INSERT 637vkjsrwpi3 4456
RECEIVED OBJECT MESSAGE 637vkjsrwpi3 4456
INSERT v3ugf4y8ckrz 3271
RECEIVED OBJECT MESSAGE v3ugf4y8ckrz 3271
INSERT 1fle12g0d0zx5 8707
RECEIVED OBJECT MESSAGE 1fle12g0d0zx5 8707
INSERT 1xej9zfi0t8dm 2928
RECEIVED OBJECT MESSAGE 1xej9zfi0t8dm 2928
UPDATE pwiwzjaoubbk 8390
INSERT 1f70u0ia40x6k 401
RECEIVED OBJECT MESSAGE 1f70u0ia40x6k 401
UPDATE art5ao3f00em 9900
INSERT vn759fh7ubd0 1720
RECEIVED OBJECT MESSAGE vn759fh7ubd0 1720
INSERT 1w1bllg3eosbz 7590
RECEIVED OBJECT MESSAGE 1w1bllg3eosbz 7590
UPDATE 9pxmv4vpmddc 9141
INSERT w6nh1tlqir3t 8431
RECEIVED OBJECT MESSAGE w6nh1tlqir3t 8431
INSERT 111j0mkmjrhlr 7553
RECEIVED OBJECT MESSAGE 111j0mkmjrhlr 7553
INSERT hyg2h3m7qgd8 7779
RECEIVED OBJECT MESSAGE hyg2h3m7qgd8 7779
INSERT 14nkhq5vf2fs8 4448
RECEIVED OBJECT MESSAGE 14nkhq5vf2fs8 4448
INSERT 15xckpgp1svzs 4840
RECEIVED OBJECT MESSAGE 15xckpgp1svzs 4840
INSERT 4vtaoozysimn 7844
RECEIVED OBJECT MESSAGE 4vtaoozysimn 7844
INSERT duxumkaj9u9d 837
RECEIVED OBJECT MESSAGE duxumkaj9u9d 837
INSERT njkgl8ck5yl2 5271
RECEIVED OBJECT MESSAGE njkgl8ck5yl2 5271
INSERT 1x9ykjycto7pz 29
RECEIVED OBJECT MESSAGE 1x9ykjycto7pz 29
UPDATE 7tu7toe52nw9 8115
INSERT x1y805u22iy3 6559
RECEIVED OBJECT MESSAGE x1y805u22iy3 6559
INSERT m9pbcrb569xa 367
RECEIVED OBJECT MESSAGE m9pbcrb569xa 367
UPDATE j1oi3zdc1a9h 5242
UPDATE fiqdxeb9qmqa 1877
INSERT 302l3uigwltl 6179
RECEIVED OBJECT MESSAGE 302l3uigwltl 6179
INSERT xx85e4f0zbhy 3213
RECEIVED OBJECT MESSAGE xx85e4f0zbhy 3213
INSERT veji44ccim7q 188
RECEIVED OBJECT MESSAGE veji44ccim7q 188
INSERT sx7u7fe5gq30 6652
RECEIVED OBJECT MESSAGE sx7u7fe5gq30 6652
INSERT 1w8ryh4viycl8 4882
RECEIVED OBJECT MESSAGE 1w8ryh4viycl8 4882
INSERT 100ahar3u9h9x 2920
RECEIVED OBJECT MESSAGE 100ahar3u9h9x 2920
INSERT vwgz1hmx2ty4 72
RECEIVED OBJECT MESSAGE vwgz1hmx2ty4 72
INSERT 1erhw9czpwzpo 4113
RECEIVED OBJECT MESSAGE 1erhw9czpwzpo 4113
INSERT 95vj41irgy5u 3379
RECEIVED OBJECT MESSAGE 95vj41irgy5u 3379
INSERT 1gh5lvz2o9xnw 4171
RECEIVED OBJECT MESSAGE 1gh5lvz2o9xnw 4171
INSERT 18isrf6smcuh1 2392
RECEIVED OBJECT MESSAGE 18isrf6smcuh1 2392
INSERT 1tiek05d1byq2 511
RECEIVED OBJECT MESSAGE 1tiek05d1byq2 511
INSERT 1am7ssut5lhw6 1647
RECEIVED OBJECT MESSAGE 1am7ssut5lhw6 1647
INSERT 1mepqwdhs4a14 7800
RECEIVED OBJECT MESSAGE 1mepqwdhs4a14 7800
UPDATE 1btsuhaqfxheg 7232
INSERT 1axl8f9uwwiza 9581
RECEIVED OBJECT MESSAGE 1axl8f9uwwiza 9581
INSERT 1r8ctl0p5sojt 3607
RECEIVED OBJECT MESSAGE 1r8ctl0p5sojt 3607
UPDATE r09sraod9bdu 9494
INSERT 1oxjinecd0x1t 8898
RECEIVED OBJECT MESSAGE 1oxjinecd0x1t 8898
INSERT ubbramifgk2l 7782
RECEIVED OBJECT MESSAGE ubbramifgk2l 7782
UPDATE 1s0h223s7gmcp 5523
UPDATE 1fjirpbx38a21 4219
INSERT 7vdwh61fljb7 6492
RECEIVED OBJECT MESSAGE 7vdwh61fljb7 6492
UPDATE 4uuxh5dxormc 244
UPDATE 1wtvmom1lmwm8 9559
INSERT wu47ep5bxl2o 4597
RECEIVED OBJECT MESSAGE wu47ep5bxl2o 4597
INSERT 1icnimpttk4px 4539
RECEIVED OBJECT MESSAGE 1icnimpttk4px 4539
UPDATE 112vbkll1rj32 1642
UPDATE qub5j6dhxlqm 4851
UPDATE 90pt6t3vrrwv 5812
INSERT 1j39u3t15rvm4 8527
RECEIVED OBJECT MESSAGE 1j39u3t15rvm4 8527
UPDATE pvrxzd0n4iu7 1087
INSERT 1vzia89yavuuf 1959
RECEIVED OBJECT MESSAGE 1vzia89yavuuf 1959
INSERT 1nq2d0t41i47k 8819
RECEIVED OBJECT MESSAGE 1nq2d0t41i47k 8819
UPDATE xs8ick4ea6s2 4154
INSERT 1p0zwzuk5ah6b 5207
RECEIVED OBJECT MESSAGE 1p0zwzuk5ah6b 5207
INSERT 1gfatuxk2o62j 4241
RECEIVED OBJECT MESSAGE 1gfatuxk2o62j 4241
INSERT evgpnsmtvk5j 259
INSERT 1xliyynq7e0li 8309
RECEIVED OBJECT MESSAGE evgpnsmtvk5j 259
UPDATE 5s65mfw0uxo6 4748
RECEIVED OBJECT MESSAGE 1xliyynq7e0li 8309
UPDATE 151ot0gb16gc 7844
INSERT 9hrb8vo6bxdd 4201
RECEIVED OBJECT MESSAGE 9hrb8vo6bxdd 4201
INSERT laqk54r7rfwb 7216
RECEIVED OBJECT MESSAGE laqk54r7rfwb 7216
UPDATE 1grmm4am2frd5 7082
INSERT q2c0b960x97e 5383
RECEIVED OBJECT MESSAGE q2c0b960x97e 5383
UPDATE 1itkw8bmozyd1 8031
INSERT 1f2m3mtwe5cv8 518
RECEIVED OBJECT MESSAGE 1f2m3mtwe5cv8 518
UPDATE g5kf2dr94i2q 9129
UPDATE 14tafi90oyyc5 9494

We have also showed how a Spring Hibernate application can be migrated from JBoss AS7 to WebLogic 12c (or vice versa). The things to keep in mind when migrating Spring from one application server to another, is the classloading and how the used resources are to be configured on the application server.

References

[1] The Red Hat product reference library.
[2] JBoss Web Framework Kit 2: Spring Installation Guide for use with JBoss Web Framework Kit Edition 2.0.0.
[3] HornetQ User Manual.
[3] Spring Framework Reference Documentation.
[4] JMS (Java Message Service).


Spring and JBoss AS7 JMS

In this post we are going to look at how we can set-up a client (build using Spring) that uses the JBoss JMS provider HornetQ remotely.

Remoting

Let us first look at how we can obtain objects remotely. In the Fun with JBoss post we have created an application that contains a stateless enterprise bean. This gives us a nice playground to call this stateless enterprise bean remotely. In order to do this we can use the following program

package test;

import model.entities.Person;
import model.logic.Company;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Properties;
import java.util.Random;

public class Test {
    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
        properties.put(Context.PROVIDER_URL, "remote://192.168.1.150:4447");
        properties.put(Context.SECURITY_PRINCIPAL, "employee");
        properties.put(Context.SECURITY_CREDENTIALS, "welcome1");
        properties.put("jboss.naming.client.ejb.context", true);

        try {
            Context context = new InitialContext(properties);
            Company company = (Company) context.lookup("LoadTest6/Model/Company!model.logic.Company");
            company.insertPerson(createPerson());
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }

    private static Person createPerson() {
        Person person = new Person();
        Random generator = new Random();
        person.setNaam(Long.toString(Math.abs(generator.nextLong()), 36));
        person.setSofinummer(1);
        return person;
    }
}

There are some points worth mentioning:

  • We need jboss-client-7.1.0.Final.jar in the client’s class path. The jar file can be obtained from the $JBOSS_HOME/bin/client directory of a JBoss AS7.1 distribution.
  • An application user must be created. This can be accomplished by using add-user.sh, located in the $JBOSS_HOME/bin directory. Detailed steps can be found in the Building a Coherence Cluster with Multiple Application Servers post. This user is then used to set the principal and credentials of the naming context that will be set-up.
  • Only JNDI objects prepended by java:jboss/exported/ can be obtained remotely. In the example, in which we obtain a stateless enterprise bean remotely, the object is bound as follows: app-name/module-name/bean-name!bean-interface in which,
    • app-name: the name of the .ear (without the .ear suffix) or the application name configured via application.xml deployment descriptor. If the application is not packaged in an .ear then there will be no app-name part to the JNDI string.
    • module-name: the name of the .jar or .war (without the .jar/.war suffix) in which the bean is deployed or the module-name configured in web.xml/ejb-jar.xml of the deployment. The module name is mandatory in the JNDI string.
    • bean-name: the name of the bean which by default is the simple name of the bean implementation class. It can be overridden either by using the name attribute of the bean defining annotation (@Stateless(name = "Company") in this case) or the ejb-jar.xml deployment descriptor.
    • bean-interface: the fully qualified class name of the interface being exposed by the bean.

When this is all to confusing for comfort, the logging will help, as something like the following output will be present when an application is deployed that contains enterprise beans:

16:50:52,840 INFO  [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-3) JNDI bindings for session bean named Company in deployment unit subdeployment "Model.jar" of deployment "LoadTest6.ear" are as follows:

java:global/LoadTest6/Model/Company!model.logic.Company
java:app/Model/Company!model.logic.Company
java:module/Company!model.logic.Company
java:jboss/exported/LoadTest6/Model/Company!model.logic.Company
java:global/LoadTest6/Model/Company
java:app/Model/Company
java:module/Company

Here, we see which objects are bound under the java:jboss/exported/ name-space that can be obtained remotely. In our example, we can use context.lookup("LoadTest6/Model/Company!model.logic.Company") to obtain an instance of the enterprise bean. Note that we must not include java:jboss/exported/, as the remote-naming project expects it to always be relative to the java:jboss/exported/ name-space.

Set-up a JBoss JMS Provider

In the domain configuration file, we have the following

<domain xmlns="urn:jboss:domain:1.1">

    <extensions>
		...
        <extension module="org.jboss.as.messaging"/>
		...
    </extensions>

	<profiles>
		<profile name="cluster">
			...
		    <subsystem xmlns="urn:jboss:domain:messaging:1.1">
                <hornetq-server>
                    <persistence-enabled>true</persistence-enabled>
                    <journal-file-size>102400</journal-file-size>
                    <journal-min-files>2</journal-min-files>

                    <connectors>
                        <netty-connector name="netty" socket-binding="messaging"/>
						...
                    </connectors>

                    <acceptors>
                        <netty-acceptor name="netty" socket-binding="messaging"/>
						...
                    </acceptors>

                    <security-settings>
                        <security-setting match="#">
                            <permission type="send" roles="guest"/>
                            <permission type="consume" roles="guest"/>
                            <permission type="createNonDurableQueue" roles="guest"/>
                            <permission type="deleteNonDurableQueue" roles="guest"/>
                        </security-setting>
                    </security-settings>

					...

                    <jms-connection-factories>
						...
                        <connection-factory name="RemoteConnectionFactory">
                            <connectors>
                                <connector-ref connector-name="netty"/>
                            </connectors>
                            <entries>
                                <entry name="RemoteConnectionFactory"/>
                                <entry name="java:jboss/exported/jms/RemoteConnectionFactory"/>
                            </entries>
                        </connection-factory>
						...
                    </jms-connection-factories>

                    <jms-destinations>
                        <jms-queue name="testQueue">
                            <entry name="java:/queue/test"/>
                            <entry name="java:jboss/exported/jms/queue/test"/>
                        </jms-queue>
						...
                    </jms-destinations>
                </hornetq-server>
            </subsystem>
		</profile>
	</profiles>

	<interfaces>
        <interface name="management"/>
        <interface name="public"/>
        <interface name="unsecure"/>
    </interfaces>

    <socket-binding-groups>
        <socket-binding-group name="cluster-sockets" default-interface="public">
			...
            <socket-binding name="messaging" port="5445"/>
			...
        </socket-binding-group>
    </socket-binding-groups>

    <deployments>
        <deployment name="LoadTest6.ear" runtime-name="LoadTest6.ear">
            <content sha1="161f51dde7f085c822cc4c68b306d57f1bee902d"/>
        </deployment>
    </deployments>

    <server-groups>
        <server-group name="cluster-group" profile="cluster">
            <jvm name="default"/>
            <socket-binding-group ref="cluster-sockets"/>
            <deployments>
                <deployment name="LoadTest6.ear" runtime-name="LoadTest6.ear" enabled="false"/>
            </deployments>
        </server-group>
    </server-groups>

</domain>

The host configuration is set-up as follows:

<host name="jboss" xmlns="urn:jboss:domain:1.1">

    <management>
        <security-realms>
            <security-realm name="ManagementRealm">
                <authentication>
                    <properties path="mgmt-users.properties" relative-to="jboss.domain.config.dir"/>
                </authentication>
            </security-realm>
            <security-realm name="ApplicationRealm">
                <authentication>
                    <properties path="application-users.properties" relative-to="jboss.domain.config.dir" />
                </authentication>
            </security-realm>
        </security-realms>
        <management-interfaces>
            <native-interface security-realm="ManagementRealm">
                <socket interface="management" port="${jboss.management.native.port:9999}"/>
            </native-interface>
            <http-interface security-realm="ManagementRealm">
                <socket interface="management" port="${jboss.management.http.port:9990}"/>
            </http-interface>
        </management-interfaces>
    </management>

    <domain-controller>
       <local/>
    </domain-controller>

    <interfaces>
        <interface name="management">
            <nic name="eth0"/>
        </interface>
        <interface name="public">
            <nic name="eth0"/>
        </interface>
        <interface name="unsecure">
            <inet-address value="127.0.0.1"/>
        </interface>
    </interfaces>

    <jvms>
    	<jvm name="default">
            <heap size="512m" max-size="512m"/>
            <permgen size="256m" max-size="256m"/>
            <jvm-options>
                <option value="-server"/>
                <option value="-XX:NewRatio=2"/>
                <option value="-XX:+UseParallelGC"/>
                <option value="-XX:ParallelGCThreads=2"/>
                <option value="-XX:MaxGCPauseMillis=200"/>
                <option value="-XX:GCTimeRatio=19"/>
                <option value="-XX:+UseParallelOldGC"/>
            </jvm-options>
        </jvm>
    </jvms>

    <servers>
        <server name="cluster-server1" group="cluster-group" auto-start="false">
        </server>
        <server name="cluster-server2" group="cluster-group" auto-start="false">
            <socket-bindings port-offset="1"/>
        </server>
    </servers>
</host>

Some points are worth mentioning in the above configuration:

  • In the host configuration, we have set-up two servers: cluster-server1 and cluster-server2. Note that these servers are bound to the cluster-group server group.
  • The server group is defined in the domain configuration and coupled to the cluster profile, the default JVM (defined in the host configuration), and the cluster-sockets socket binding group.
  • The default interface that cluster-sockets socket binding group uses, is the public interface. The public interface is configured to use the network interface card in this case eth0 (see the host configuration).
  • The messaging socket binding is part of the cluster-sockets socket binding group.
  • The netty connector is configured to use the messaging socket-binding.
  • The RemoteConnectionFactory is configured to use the netty connector so when a client looks up this connection factory it will receive this netty connector which will tell the client where to connect. A remark is in order: Once we get the JMS connection factory reference from the server by looking it up in JNDI and use it to create a connection, the final destination of the connection has nothing to do with the java.naming.provider.url (Context.PROVIDER_URL) that was used in the JNDI lookup. When looking up a connection factory in JNDI, the client gets a connector which is a simple stub telling the client where its connections should go. In this case the connections are bound to the network interface card and the port defined in the messaging socket binding.

Using JBoss JMS Remotely

To interact remotely with the JBoss JMS provider (HornetQ) we can use the following program to test (before we put everything into Spring)

package model.test;

import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Properties;

public class JNDITest {
    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
        properties.put(Context.PROVIDER_URL, "remote://192.168.1.150:4447");
        properties.put(Context.SECURITY_PRINCIPAL, "employee");
        properties.put(Context.SECURITY_CREDENTIALS, "welcome1");

        ConnectionFactory connectionFactory = null;
        Destination destination = null;

        try {
            Context context = new InitialContext(properties);
            connectionFactory = (ConnectionFactory) context.lookup("jms/RemoteConnectionFactory");
            destination = (Destination) context.lookup("jms/queue/test");

            System.out.println(connectionFactory);
            System.out.println(destination);

            sendMessage(connectionFactory, destination);
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }

    private static void sendMessage(ConnectionFactory connectionFactory, Destination destination) {
        Connection connection = null;
        Session session = null;
        MessageProducer messageProducer = null;

        try {
            connection = connectionFactory.createConnection("employee", "welcome1");
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            messageProducer = session.createProducer(destination);

            TextMessage text = session.createTextMessage();
            text.setText("Send some useful message");
            messageProducer.send(text);
        } catch (JMSException e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (JMSException f) {
                    f.printStackTrace();
                }
            }
        }

    }
}

One (or more) of the following exceptions can be encountered when running the program:

  1. Caused by: HornetQException[errorCode=2 message=Cannot connect to server(s). Tried with all available servers.]
  2. Caused by: HornetQException[errorCode=105 message=Unable to validate user: null]
  3. javax.jms.JMSSecurityException: User: employee doesn’t have permission=’SEND’ on address jms.queue.test

The first exception is usually due to a host mismatch. Note that we are using the netty connector for the RemoteConnectionFactory. The netty connector uses the following (NettyConnector.java) to obtain an address:

    remoteDestination = new InetSocketAddress(host, port);
    InetAddress inetAddress = ((InetSocketAddress) remoteDestination).getAddress();

So what address would that be? To check this we can use the following

import java.net.InetAddress;

public class WhatIsMyAddress {
    public static void main(String[] args) throws Exception {
        System.out.println(InetAddress.getLocalHost());
    }
}

When this program is run we get the following output:

[jboss@axis-into-ict temp]$ /home/jboss/jdk1.6.0_31/bin/java WhatIsMyAddress
axis-into-ict.nl/192.168.1.150

When we run the test to interact with the JBoss JMS provider remotely, we get the following

Aug 10, 2012 10:48:44 AM org.xnio.Xnio <clinit>
INFO: XNIO Version 3.0.3.GA
Aug 10, 2012 10:48:44 AM org.xnio.nio.NioXnio <clinit>
INFO: XNIO NIO Implementation Version 3.0.3.GA
Aug 10, 2012 10:48:44 AM org.jboss.remoting3.EndpointImpl <clinit>
INFO: JBoss Remoting version 3.2.2.GA
HornetQConnectionFactory [serverLocator=ServerLocatorImpl [initialConnectors=[org-hornetq-core-remoting-impl-netty-NettyConnectorFactory?port=5445&host=axis-into-ict-nl], discoveryGroupConfiguration=null], clientID=null, dupsOKBatchSize=1048576, transactionBatchSize=1048576, readOnly=false]
HornetQQueue[testQueue]

One important thing to note here, is that the host is set to axis-into-ict-nl instead of the expected axis-into-ict.nl, i.e., in the host the ‘.’ are replaced by ‘-’. In order to get the axis-into-ict-nl to be resolved to the right IP address we add this to the etc/hosts file on the client

192.168.1.150       axis-into-ict.nl axis-into-ict-nl

The second exception is because no user is provided in the creation of a connection, i.e., connection = connectionFactory.createConnection(); is used instead of connection = connectionFactory.createConnection("employee", "welcome1").

The third exception is because the provided user to create a connection does not have the right privileges. Note that in the JMS configuration the following is present

<security-settings>
    <security-setting match="#">
        <permission type="send" roles="guest"/>
        <permission type="consume" roles="guest"/>
        <permission type="createNonDurableQueue" roles="guest"/>
        <permission type="deleteNonDurableQueue" roles="guest"/>
    </security-setting>
</security-settings>

This means the user must have the guest role. To accomplish this edit the application-roles.properties file (located in the $JBOSS_HOME/domain/configuration directory) and add the guest role to the used user, for example,

employee=guest,EMPLOYEE
manager=MANAGER

Restart the server such that the changes are picked up.

Create the Spring Client

Now that we have everything in place we can set-up the Spring configuration, for example,

<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 id="jnditemplate" class="org.springframework.jndi.JndiTemplate">
        <property name="environment">
            <props>
                <prop key="java.naming.factory.initial">org.jboss.naming.remote.client.InitialContextFactory</prop>
                <prop key="java.naming.provider.url">remote://192.168.1.150:4447</prop>
                <prop key="java.naming.security.principal">employee</prop>
                <prop key="java.naming.security.credentials">welcome1</prop>
            </props>
        </property>
    </bean>
    <bean id="connectionfactory" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="jnditemplate"/>
        <property name="jndiName" value="jms/RemoteConnectionFactory"/>
    </bean>
    <bean id="destination" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="jnditemplate"/>
        <property name="jndiName" value="jms/queue/test"/>
    </bean>
    <bean id="credentialsconnectionfactory"
          class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
        <property name="targetConnectionFactory" ref="connectionfactory"/>
        <property name="username" value="employee"/>
        <property name="password" value="welcome1"/>
    </bean>
    <bean id="jmstemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="credentialsconnectionfactory"/>
        <property name="defaultDestination" ref="destination"/>
    </bean>
    <bean class="org.springframework.jms.listener.SimpleMessageListenerContainer">
        <property name="connectionFactory" ref="credentialsconnectionfactory"/>
        <property name="destination" ref="destination"/>
        <property name="messageListener" ref="receiver"/>
    </bean>
    <bean id="sender" class="model.logic.JMSSender">
        <property name="jmsTemplate" ref="jmstemplate"/>
    </bean>
    <bean id="receiver" class="model.logic.JMSReceiver"/>
</beans>

in which, the referred classes JMSSender and JMSReceiver look as follows

package model.logic;

import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import java.util.Random;

public class JMSSender {

    private Random generator = new Random();
    private JmsTemplate jmsTemplate;

    public JMSSender() {
    }

    public JmsTemplate getJmsTemplate() {
        return jmsTemplate;
    }

    public void setJmsTemplate(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    public void sendMessage() {
        getJmsTemplate().send(new MessageCreator(){
            public Message createMessage(Session session) throws JMSException {
                TextMessage message = session.createTextMessage();
                message.setText(Long.toString(Math.abs(generator.nextLong()), 36));
                return message;
            }
        });
    }
}
package model.logic;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

public class JMSReceiver implements MessageListener {
    public JMSReceiver() {
    }

    public void onMessage(Message message) {
        TextMessage text = (TextMessage)message;
        try {
            message.acknowledge();
            System.out.println("received the following message: " + text.getText());
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

To test the set-up we can use

package model.test;

import model.logic.JMSSender;
import model.utils.SpringUtilities;

public class JMSTest {

    public static void main(String[] args) {
        JMSSender jmsSender = SpringUtilities.getJMSSender();

        while (true) {
            jmsSender.sendMessage();
            System.out.println("done sending message");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

When the test is run the following output is observed

Aug 10, 2012 11:19:41 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1ed2ae8: startup date [Fri Aug 10 11:19:41 CEST 2012]; root of context hierarchy
Aug 10, 2012 11:19:41 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring-config.xml]
Aug 10, 2012 11:19:41 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@ef5502: defining beans [jnditemplate,connectionfactory,destination,credentialsconnectionfactory,jmstemplate,org.springframework.jms.listener.SimpleMessageListenerContainer#0,sender,receiver]; root of factory hierarchy
Aug 10, 2012 11:19:41 AM org.xnio.Xnio <clinit>
INFO: XNIO Version 3.0.3.GA
Aug 10, 2012 11:19:41 AM org.xnio.nio.NioXnio <clinit>
INFO: XNIO NIO Implementation Version 3.0.3.GA
Aug 10, 2012 11:19:41 AM org.jboss.remoting3.EndpointImpl <clinit>
INFO: JBoss Remoting version 3.2.2.GA
Aug 10, 2012 11:19:42 AM org.jboss.naming.remote.protocol.v1.RemoteNamingStoreV1$MessageReceiver handleEnd
ERROR: Channel end notification received, closing channel Channel ID b3d15ef8 (outbound) of Remoting connection 009ffe3f to /192.168.1.150:4447
Aug 10, 2012 11:19:42 AM org.jboss.naming.remote.protocol.v1.RemoteNamingStoreV1$MessageReceiver handleEnd
ERROR: Channel end notification received, closing channel Channel ID c4cd8d30 (outbound) of Remoting connection 0032060c to /192.168.1.150:4447
Aug 10, 2012 11:19:42 AM org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup start
INFO: Starting beans in phase 2147483647
received the following message: Send some useful message
received the following message: q9em87lq59pb
done sending message
received the following message: 9l1e70x6e2yf
done sending message
received the following message: 1e0fqxcfs0os5
done sending message
received the following message: 8bcprios0t56
done sending message
received the following message: 1elnsn5m1sxf1
done sending message
received the following message: 5cnl5bt1ztp8
done sending message
received the following message: 1tnm5yf1dn6fx
done sending message
received the following message: j8efslaqykc6
done sending message
received the following message: t10r3842i2fi
done sending message
received the following message: j845q4yhyrgn
done sending message
received the following message: 4ky8mbz8h7kl
done sending message
received the following message: y5go5h1iwcl0
done sending message
received the following message: 5j6buhmnq9up
done sending message
received the following message: 1wdojt8n3kztv
done sending message
received the following message: 1k6p9352nwcgl
done sending message
received the following message: 1povempe0r3ju
done sending message

References

[1] EJB invocations from a remote client using JNDI.
[2] Remote EJB invocations via JNDI – EJB client API or remote-naming project.
[3] EJB invocations from a remote server instance.


WebLogic Messaging Bridge and Store-and-Forward Service

In this post we first set-up a WebLogic environment that uses the WebLogic Messaging Bridge to forward messages. Next, we use the store-and-forward service to do the same. We will use Spring to test the set-ups. We end the post by looking at some performance considerations.

Messaging bridge

The WebLogic messaging bridge is a forwarding mechanism that provides interoperability between WebLogic JMS implementations, and between JMS and other messaging products. Use the Messaging Bridge to integrate messaging applications between:

  • Any two implementations of WebLogic JMS, including those from separate releases of WebLogic Server
  • WebLogic JMS implementations that reside in separate WebLogic domains
  • WebLogic JMS and a third-party JMS product

A messaging bridge instance forwards messages between a pair of bridge source and target destinations. These destinations are mapped to a pair of bridge source and target destinations. The messaging bridge reads messages from the source bridge destination and forwards those messages to the target bridge destination. For WebLogic JMS and third-party JMS products, a messaging bridge communicates with source and target destinations using the Java EE Connector Architecture (JCA) resource adapters provided with WebLogic Server. Two resource adapters are provided, i.e.,

  • eis.jms.WLSConnectionFactoryJNDIXA – Provides transaction semantics. Used when the required quality of service (QOS) is exactly-once (the message will be delivered from the sending destination to the receiving destination using XA transactions so that the receiver gets exactly one copy of each message). This envelopes a received message and sends it within a user transaction (XA/JTA). The following requirements apply to use of this resource adapter:
    • Any WebLogic Server implementation being bridged must be release 7.0 or later
    • The source and target JMS connection factories must be configured to use the XAConnectionFactory
  • eis.jms.WLSConnectionFactoryJNDINoTX – Provides no transaction semantics. Used when the required QOS is atmost-once (Makes sure that the receiving destination receives only a single copy of the message or does not receive it at all) or duplicate-okay (the bridge acknowledges receiving the message from the source destination only after writing it to the target destination, because this is done outside the scope of a transaction, failures after writing the message to the target and before acknowledging the source can result in duplicate messages being delivered but should never result in a message being lost, this type of delivery is better known as at-least-once delivery). If the requested QOS is atmost-once, the resource adapter uses AUTO_ACKNOWLEDGE mode. If the requested QOS is duplicate-okay, CLIENT_ACKNOWLEDGE is used.

An instance of the messaging bridge maps each source destination with a target destination. Each destination is configured using one of the adapters. Each bridge instance is targeted to a specific WebLogic Server instance. If the source is a distributed destination, the JMS consumer load balancing rules will associate the bridge with a single destination. In this case, it is best to connect a separate bridge instance to each member of the source destination. This leads to a proliferation of bridge instances that must be reconfigured if the cluster membership changes. The messaging bridge must be used when storing and forwarding messages between JMS destinations where one or both destinations are either hosted by foreign JMS providers or running on older versions of WebLogic Server (prior 9.0) that do not support the store-and-forward service.

Configuration

To set-up a messaging bridge, we need to first set-up the JMS resources involved in the bridge, i.e., the connection factories and destinations. In the example below we use two WebLogic environments. On one WebLogic environment we create the following:

  • Persistent store targeted to the admin server
  • JMS Server targeted to the admin server
  • JMS Module targeted to the admin server with the following resources:
    • Connection Factory default targeting enabled, with JNDI jms/BridgeConnectionFactory (and is XA enabled)
    • Destination (Queue) targeted through a sub deployment to the JMS Server, with JNDI jms/BridgeCompanyQueue

On the other environment we create the following:

  • A cluster consisting of two managed servers
  • Two JMS servers each targeted to a migratable target belonging to a managed server in the cluster (note that a migratable target is automatically created when a managed server is clustered
  • Two persistent stores each targeted to a managed server in the cluster
  • JMS module targeted to the cluster with the following resources:
    • Connection Factory default targeting enabled, with JNDI jms/ConnectionFactory (and is XA enabled)
    • Uniform distributed destination (queue) targeted through a subdeployment to the JMS Servers, with JNDI jms/CompanyQueue

Next, we configure two JMS bridge destinations. One source destination from which the messaging bridge instance reads messages and one target destination where the messaging bridge instance sends the messages it receives from the source destination. In the admin console

  • Open the tree services, messaging, bridges
  • Click JMS bridge destinations, click new and enter the following parameters:
    • Name: SourceDestination
    • Adapter JNDI Name: eis.jms.ConnectionFactoryJNDINoTx
    • Adapter Classpath: When connecting to a third-party JMS product, the bridge destination must supply the product’s CLASSPATH in the WebLogic Server CLASSPATH.
    • Connection URL: t3://192.168.1.50:7001
    • Connection Factory JNDI Name: jms/BridgeConnectionFactory
    • Destination JNDI Name: jms/BridgeCompanyQueue
  • Click OK

The target destination is configured as

  • Open the tree services, messaging, bridges
  • Click JMS bridge destinations, click new and enter the following parameters:
    • Name: TargetDestination
    • Adapter JNDI Name: eis.jms.ConnectionFactoryJNDINoTx
    • Adapter Classpath: When connecting to a third-party JMS product, the bridge destination must supply the product’s CLASSPATH in the WebLogic Server CLASSPATH.
    • Connection URL: t3://192.168.1.50:9001,192.168.1.50:9002
    • Connection Factory JNDI Name: jms/ConnectionFactory
    • Destination JNDI Name: jms/CompanyQueue
  • Click OK

The actual messaging bridge can be created as follows:

  • Open the tree services, messaging, bridges
  • Click new and enter the following parameters:
    • Name: WebLogicToWebLogicBridge
    • Selector: can be left empty
    • Quality Of Service: atmost-once
    • Started: enabled
  • Click next and select the source destination in our case this is SourceDestination
  • Click next and select the messaging provider in our case this is WebLogic Server 7.0 or higher
  • Click next and select the target destination in our case this is TargetDestination
  • Click next and select the messaging provider for the target in our case this is WebLogic Server 7.0 or higher
  • Click next and target the messaging bridge to the server that holds to the source destination, which is our case is the adminserver
  • Click next and click finish

Note that after the creation the messaging bridge can be fine tuned.

WLST

The following script shows an example how the messaging bridge can be set-up using WLST

print 'CONNECT TO ADMIN SERVER';
connect('weblogic', 'magic12c', 't3://192.168.1.50:7001');

print 'START EDIT MODE';
edit();
startEdit();

print 'CREATE SOURCE JMS BRIDGE DESTINATION';
cmo.createJMSBridgeDestination('SourceDestination');
sourcedestination = cmo.lookupJMSBridgeDestination('SourceDestination');
sourcedestination.setClasspath('');
sourcedestination.setConnectionURL('t3://192.168.1.50:7001');
sourcedestination.setAdapterJNDIName('eis.jms.WLSConnectionFactoryJNDINoTX');
sourcedestination.setConnectionFactoryJNDIName('jms/BridgeConnectionFactory');
sourcedestination.setDestinationJNDIName('jms/BridgeCompanyQueue');

print 'CREATE TARGET JMS BRIDGE DESTINATION';
cmo.createJMSBridgeDestination('TargetDestination');
targetdestination = cmo.lookupJMSBridgeDestination('TargetDestination');
targetdestination.setClasspath('');
targetdestination.setConnectionURL('t3://192.168.1.50:9001,192.168.1.50:9002');
targetdestination.setAdapterJNDIName('eis.jms.WLSConnectionFactoryJNDINoTX');
targetdestination.setConnectionFactoryJNDIName('jms/ConnectionFactory');
targetdestination.setDestinationJNDIName('jms/CompanyQueue');

print 'CREATE MESSAGING BRIDGE';
cmo.createMessagingBridge('Bridge');
bridge = cmo.lookupMessagingBridge('Bridge');
adminserver = cmo.lookupServer('AdminServer');
targets = bridge.getTargets();
targets.append(adminserver);
bridge.setTargets(targets);
bridge.setSourceDestination(sourcedestination);
bridge.setTargetDestination(targetdestination);
bridge.setStarted(true);
bridge.setSelector('');
bridge.setQualityOfService('Atmost-once');

print 'SAVE AND ACTIVATE CHANGES';
save();
activate(block='true');

Test

To test if the set-up works we will use a Spring client. Make sure the wlclient and wljmsclient jar files are on the classpath. To set-up a JMS producer using Spring we can use the following configuration:

<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 id="sourceJndiTemplate" class="org.springframework.jndi.JndiTemplate">
        <property name="environment">
            <props>
                <prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
                <prop key="java.naming.provider.url">t3://192.168.1.50:7001</prop>
            </props>
        </property>
    </bean>
    <bean id="sourceConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="sourceJndiTemplate"/>
        <property name="jndiName" value="jms/BridgeConnectionFactory"/>
    </bean>
    <bean id="sourceDestination" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="sourceJndiTemplate"/>
        <property name="jndiName" value="jms/BridgeCompanyQueue"/>
    </bean>
    <bean id="sourceJmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="sourceConnectionFactory"/>
        <property name="defaultDestination" ref="sourceDestination"/>
    </bean>
    <bean id="sender" class="model.logic.JMSSender">
        <property name="jmsTemplate" ref="sourceJmsTemplate"/>
    </bean>
</beans>

To send a message by using the configured JMSTemplate we can use the following class:

package model.logic;

import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import java.util.Random;

public class JMSSender {

    private Random generator = new Random();
    private JmsTemplate jmsTemplate;

    public JMSSender() {
    }

    public JmsTemplate getJmsTemplate() {
        return jmsTemplate;
    }

    public void setJmsTemplate(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    public void sendMessage() {
        getJmsTemplate().send(new MessageCreator(){
            public Message createMessage(Session session) throws JMSException {
                TextMessage message = session.createTextMessage();
                message.setText(Long.toString(Math.abs(generator.nextLong()), 36));
                return message;
            }
        });
    }
}

To run the class we can use:

package model.test;

import model.logic.JMSSender;
import model.utils.SpringUtilities;

public class JMSTest {

    public static void main(String[] args) {
        JMSSender jmsSender = SpringUtilities.getJMSSender();
        jmsSender.sendMessage();
    }
}

To consume a message we create another client using Spring’s SimpleMessageListenerContainer. We have the following configuration:

<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 id="targetJndiTemplate" class="org.springframework.jndi.JndiTemplate">
        <property name="environment">
            <props>
                <prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
                <prop key="java.naming.provider.url">t3://192.168.1.50:9001,192.168.1.50:9002</prop>
            </props>
        </property>
    </bean>
    <bean id="targetConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="targetJndiTemplate"/>
        <property name="jndiName" value="jms/ConnectionFactory"/>
    </bean>
    <bean id="targetDestination" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="targetJndiTemplate"/>
        <property name="jndiName" value="jms/CompanyQueue"/>
    </bean>
    <bean class="org.springframework.jms.listener.SimpleMessageListenerContainer">
        <property name="connectionFactory" ref="targetConnectionFactory"/>
        <property name="destination" ref="targetDestination"/>
        <property name="messageListener" ref="receiver"/>
    </bean>
    <bean id="receiver" class="model.logic.JMSReceiver"/>
</beans>

To receive a message asynchronously we use:

package model.logic;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

public class JMSReceiver implements MessageListener {
    public JMSReceiver() {
    }

    public void onMessage(Message message) {
        TextMessage text = (TextMessage)message;
        try {
            message.acknowledge();
            System.out.println("received the following message: " + text.getText());
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

Store-and-forward service

The Store-and-Forward (SAF) service enables WebLogic Server to deliver messages reliably between applications that are distributed across WebLogic Server instances. JMS modules utilize the SAF service to enable local JMS message producers to reliably send messages to remote queues or topics without worrying about the availability of the remote environment. If the destination is not available at the moment the messages are sent, either because of network problems or system failures, then the messages are saved on a local server instance, and are forwarded to the remote destination once it becomes available. The SAF Service should be used when forwarding JMS messages between WebLogic Server 9.x or later domains. The SAF service can deliver messages:

  • Between two stand-alone server instances
  • Between server instances in a cluster
  • Across two clusters in a domain
  • Across separate domains

When not to use the SAF service:

  • Forwarding messages to prior releases of WebLogic Server
  • Interoperating with third-party JMS products. For these tasks, we should use the WebLogic Messaging Bridge
  • When using temporary destinations with the JMSReplyTo field to return a response to a request

Additionally, when using JMS SAF, an application can only receive messages directly from a remote server, and only when the remote server is available. Both the store-and-forward service and the messaging bridge provide JMS applications a message forwarding agent-based technology. A thing to note is that the store-and-forward service uses an internal duplicate elimination algorithm that does not require XA transactions and thus will perform better for the exactly-once quality of service. The store-and-forward service uses agents to store and forward the messages between the sending and receiving sides. We must configure store-and-forward agents to support sending, receiving, or both depending on the set-up being used:

  • JMS sending – only a sending agent
  • JMS receiving – no agent needed
  • Web Services Reliable Messaging sending – sending and receiving agent
  • Web Services Reliable Messaging receiving – receiving agent

SAF agents are similar to JMS servers in that they have persistent stores, paging directories, and destinations, as well as quotas, thresholds, and other similar configuration parameters. The primary difference is that SAF agents only support imported destinations, a local representation of remote destinations to which messages are stored locally and then forwarded. SAF agents also support targeting to migratable targets to enable SAF agent service migration. Reliability in SAF is time-based in that the time-to-live attribute determines how long the agent will attempt to forward the message before expiring it. When setting a time-to-live on one of the SAF objects, a value of -1 means that the value is not set, 0 means that the message never expires, and a positive value defines the number of milliseconds after the message was created that the message will expire. If a message expires, SAF error handling provides four expiration policies from which to choose: Discard, Log, Redirect, and Always-forward. Always-forward ignores the time-to-live setting on the imported destinations and any message expiration time and forwards the message even after it has expired. Typically, this option would be used if the application had expiration policies set up on the remote destinations and we want the expired messages to be handled using these policies.

Configuration

To set-up a store-and-forward service we can use the following steps. First, we create a SAF agent:

  • In the admin console click services, messaging, store and forward agent
  • Click new and enter the following parameters:
    • name: SAFAgent
    • persistent store: AdminFileStore (or create a new one)
    • agent type: sending-only
  • Click next and enter the following parameters:
    • target: AdminServer (the same as the target of the persistent store)

Next, create a JMS module or use an existing one and create a subdeployment for the SAF agent

  • Click subdeployments, click new and enter the following parameters:
    • subdeployment name: SAFSubDeployment
  • Click next and select as target the created SAF agent
  • Click finish

Subsequently, we create a remote SAF context

  • Click the configuration tab of the JMS module
  • Click new, select remote SAF context, click next and enter the following parameters:
    • name: RemoteSAFContext
    • URL: t3://192.168.1.50:9001,192.168.1.50:9002
    • username: weblogic (admin username)
    • password: magic12c (admin password)
    • confirm password: magic12c
  • Click OK

Next, create SAF imported destinations

  • Click the configuration tab of the JMS module
  • Click new, select SAF imported destinations, click next and enter the following parameters:
    • name: SAFImportedDestinations
    • JNDI prefix: jms/ (this can be used for the local destination counterparts of remote destinations to which the SAF agent is connecting)
    • remote SAF context: RemoteSAFContext
  • Click next and click advanced targeting
  • Select SAFSubDeployment and click finish

In the last step we will add remote queues to the created SAF imported destination

  • Click the create SAF imported destination
  • Click the queues, configuration tab, click new and enter the following parameters:
    • name: SAFQueue
    • remote JNDI name: jms/CompanyQueue
  • Click OK
  • Click SAFQueue and set the local JNDI name to SAFCompanyQueue (note that we can now look up the local queue by using jms/SAFCompanyQueue, in which jms/ is the JNDI prefix we set earlier)
  • Save the configuration

To check if the configuration is correct check the server logging, something like the following should be present

####<Apr 16, 2012 10:43:49 AM CEST> <Info> <JMS> <axis-into-ict.nl> <AdminServer> <[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1334565829666> <BEA-040506> <The JMS store-and-forward (SAF) forwarder has successfully connected to the remote destination "t3://192.168.1.50:9001,192.168.1.50:9002/jms/CompanyQueue".>

When the servers to which the SAF agent is connecting are not present the following exception is observed

####<Apr 16, 2012 10:43:07 AM CEST> <Info> <JMS> <axis-into-ict.nl> <AdminServer> <[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1334565787556> <BEA-040507> <The JMS store-and-forward (SAF) forwarder failed to connect to the remote destination "t3://192.168.1.50:9001,192.168.1.50:9002/jms/CompanyQueue", because of javax.naming.CommunicationException [Root exception is java.net.ConnectException: t3://192.168.1.50:9001,192.168.1.50:9002: Destination unreachable; nested exception is:
	java.net.ConnectException: Connection refused; No available router to destination]
	at weblogic.jndi.internal.ExceptionTranslator.toNamingException(ExceptionTranslator.java:40)
	at weblogic.jndi.WLInitialContextFactoryDelegate.toNamingException(WLInitialContextFactoryDelegate.java:767)
	at weblogic.jndi.WLInitialContextFactoryDelegate.getInitialContext(WLInitialContextFactoryDelegate.java:366)
	at weblogic.jndi.Environment.getContext(Environment.java:315)
	at weblogic.jndi.Environment.getContext(Environment.java:285)
	at weblogic.jndi.Environment.createInitialContext(Environment.java:208)
	at weblogic.jndi.Environment.getInitialContext(Environment.java:192)
	at weblogic.jndi.Environment.getInitialContext(Environment.java:170)
	at weblogic.jndi.Environment.getContext(Environment.java:215)
	at weblogic.jms.forwarder.Forwarder.getInitialContext(Forwarder.java:428)
	at weblogic.jms.forwarder.Forwarder.connectTarget(Forwarder.java:447)
	at weblogic.jms.forwarder.Forwarder.reconnect(Forwarder.java:270)
	at weblogic.jms.forwarder.Forwarder.timerExpired(Forwarder.java:335)
	at weblogic.timers.internal.TimerImpl.run(TimerImpl.java:293)
	at weblogic.work.SelfTuningWorkManagerImpl$WorkAdapterImpl.run(SelfTuningWorkManagerImpl.java:545)
	at weblogic.work.ExecuteThread.execute(ExecuteThread.java:256)
	at weblogic.work.ExecuteThread.run(ExecuteThread.java:221)
Caused by: java.net.ConnectException: t3://192.168.1.50:9001,192.168.1.50:9002: Destination unreachable; nested exception is:
	java.net.ConnectException: Connection refused; No available router to destination
	at weblogic.rjvm.RJVMFinder.findOrCreateInternal(RJVMFinder.java:216)
	at weblogic.rjvm.RJVMFinder.findOrCreate(RJVMFinder.java:170)
	at weblogic.rjvm.ServerURL.findOrCreateRJVM(ServerURL.java:165)
	at weblogic.jndi.WLInitialContextFactoryDelegate$1.run(WLInitialContextFactoryDelegate.java:345)
	at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:363)
	at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:146)
	at weblogic.jndi.WLInitialContextFactoryDelegate.getInitialContext(WLInitialContextFactoryDelegate.java:340)
	... 14 more
Caused by: java.rmi.ConnectException: Destination unreachable; nested exception is:
	java.net.ConnectException: Connection refused; No available router to destination
	at weblogic.rjvm.ConnectionManager.bootstrap(ConnectionManager.java:470)
	at weblogic.rjvm.ConnectionManager.bootstrap(ConnectionManager.java:321)
	at weblogic.rjvm.RJVMManager.findOrCreateRemoteInternal(RJVMManager.java:260)
	at weblogic.rjvm.RJVMManager.findOrCreate(RJVMManager.java:197)
	at weblogic.rjvm.RJVMFinder.findOrCreateRemoteServer(RJVMFinder.java:238)
	at weblogic.rjvm.RJVMFinder.findOrCreateRemoteCluster(RJVMFinder.java:316)
	at weblogic.rjvm.RJVMFinder.findOrCreateInternal(RJVMFinder.java:205)
	... 20 more
.>

As can be seen from the previous log line (which in time is happening later), when the servers become available the SAF agent connects to the servers.

WLST

The following script shows an example how the save-and-forward service can be set-up using WLST

print 'CONNECT TO ADMIN SERVER';
connect('weblogic', 'magic12c', 't3://192.168.1.50:7001');

print 'START EDIT MODE';
edit();
startEdit();

print 'CREATE FILE STORE';
cmo.createFileStore('SAFFileStore');
saffilestore = cmo.lookupFileStore('SAFFileStore');
saffilestore.setDirectory('/home/oracle/weblogic12.1.1/configuration/applications/base_domain');
targets = saffilestore.getTargets();
adminserver = cmo.lookupServer('AdminServer');
targets.append(adminserver);
saffilestore.setTargets(targets);

print 'SAVE, ACTIVATE CHANGES AND START EDIT';
save();
activate(block='true');
startEdit();

print 'CREATE SAF Agent';
cmo.createSAFAgent('SAFAgent');
safagent = cmo.lookupSAFAgent('SAFAgent');
safagent.setStore(saffilestore);
safagent.setTargets(targets);
safagent.setServiceType('Sending-only');

print 'SAVE, ACTIVATE CHANGES AND START EDIT';
save();
activate(block='true');
startEdit();

print 'CREATE JMS MODULE';
cmo.createJMSSystemResource('jms-saf-module');
safmodule = cmo.lookupJMSSystemResource('jms-saf-module');
safmodule.setTargets(targets);
safmodule.createSubDeployment('SAFSubDeployment');
cd('/JMSSystemResources/jms-saf-module/SubDeployments/SAFSubDeployment');
set('Targets',jarray.array([ObjectName('com.bea:Name=SAFAgent,Type=SAFAgent')], ObjectName));
cd('/');

print 'SAVE, ACTIVATE CHANGES AND START EDIT';
save();
activate(block='true');
startEdit();

print 'OBTAIN JMS RESOURCE';
resource = safmodule.getJMSResource();

print 'CREATE CONNECTION FACTORY';
resource.createConnectionFactory('SAFConnectionFactory');
connectionfactory = resource.lookupConnectionFactory('SAFConnectionFactory');
connectionfactory.setJNDIName('jms/SAFConnectionFactory');
connectionfactory.setDefaultTargetingEnabled(true);
connectionfactory.getTransactionParams().setTransactionTimeout(3600);
connectionfactory.getTransactionParams().setXAConnectionFactoryEnabled(true);
connectionfactory.getSecurityParams().setAttachJMSXUserId(false);
connectionfactory.getClientParams().setClientIdPolicy('Restricted');
connectionfactory.getClientParams().setSubscriptionSharingPolicy('Exclusive');
connectionfactory.getClientParams().setMessagesMaximum(10);

print 'SAVE, ACTIVATE CHANGES AND START EDIT';
save();
activate(block='true');
startEdit();

print 'CREATE SAF REMOTE CONTEXT';
resource.createSAFRemoteContext('RemoteSAFContext');
safcontext = resource.lookupSAFRemoteContext('RemoteSAFContext');
safcontext.getSAFLoginContext().setLoginURL('t3://192.168.1.50:9001,192.168.1.50:9002');
safcontext.getSAFLoginContext().setUsername('weblogic');
safcontext.getSAFLoginContext().setPassword('magic12c');

print 'SAVE, ACTIVATE CHANGES AND START EDIT';
save();
activate(block='true');
startEdit();

print 'CREATE SAF IMPORTED DESTINATIONS';
resource.createSAFImportedDestinations('SAFImportedDestinations');
importeddestinations = resource.lookupSAFImportedDestinations('SAFImportedDestinations');
importeddestinations.setJNDIPrefix('jms/');
importeddestinations.setSAFRemoteContext(safcontext);
importeddestinations.setSAFErrorHandling(None);
importeddestinations.setTimeToLiveDefault(0);
importeddestinations.setUseSAFTimeToLiveDefault(false);
importeddestinations.setSubDeploymentName('SAFSubDeployment');

print 'SAVE, ACTIVATE CHANGES AND START EDIT';
save();
activate(block='true');
startEdit();

print 'ADD QUEUE TO THE SAF IMPORTED DESTINATIONS';
importeddestinations.createSAFQueue('SAFQueue');
safqueue = importeddestinations.lookupSAFQueue('SAFQueue');
safqueue.setRemoteJNDIName('jms/CompanyQueue');
safqueue.setLocalJNDIName('SAFCompanyQueue');

print 'SAVE AND ACTIVATE CHANGES';
save();
activate(block='true');

Test

To test the set-up we will again use Spring. To set-up the sending end, we will use the following configuration

<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 id="sourceJndiTemplate" class="org.springframework.jndi.JndiTemplate">
        <property name="environment">
            <props>
                <prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
                <prop key="java.naming.provider.url">t3://192.168.1.50:7001</prop>
            </props>
        </property>
    </bean>
    <bean id="sourceConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="sourceJndiTemplate"/>
        <property name="jndiName" value="jms/SAFConnectionFactory"/>
    </bean>
    <bean id="sourceDestination" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="sourceJndiTemplate"/>
        <property name="jndiName" value="jms/SAFCompanyQueue"/>
    </bean>
    <bean id="sourceJmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="sourceConnectionFactory"/>
        <property name="defaultDestination" ref="sourceDestination"/>
    </bean>
    <bean id="timerListener" class="org.springframework.scheduling.commonj.ScheduledTimerListener">
        <property name="delay" value="10000"/>
        <property name="period" value="30000"/>
        <property name="runnable" ref="sender"/>
    </bean>
    <bean id="timerFactory" class="org.springframework.scheduling.commonj.TimerManagerFactoryBean">
        <property name="timerManagerName" value="java:comp/env/tm/default"/>
        <property name="resourceRef" value="true"/>
        <property name="scheduledTimerListeners">
            <list>
                <ref bean="timerListener"/>
            </list>
        </property>
    </bean>
    <bean id="sender" class="model.logic.JMSSender">
        <property name="jmsTemplate" ref="sourceJmsTemplate"/>
    </bean>
</beans>

in which the sender bean looks as follows

package model.logic;

import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import java.util.Random;

public class JMSSender implements Runnable {

    private Random generator = new Random();
    private JmsTemplate jmsTemplate;

    public JMSSender() {
    }

    public JmsTemplate getJmsTemplate() {
        return jmsTemplate;
    }

    public void setJmsTemplate(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    public void sendMessage() {
        getJmsTemplate().send(new MessageCreator(){
            public Message createMessage(Session session) throws JMSException {
                TextMessage message = session.createTextMessage();
                message.setText(Long.toString(Math.abs(generator.nextLong()), 36));
                return message;
            }
        });
    }

    public void run() {
        sendMessage();
    }
}

To set-up the receiving end, we will use the following configuration

<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 id="targetJndiTemplate" class="org.springframework.jndi.JndiTemplate">
        <property name="environment">
            <props>
                <prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
                <prop key="java.naming.provider.url">t3://192.168.1.50:9001,192.168.1.50:9002</prop>
            </props>
        </property>
    </bean>
    <bean id="targetConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="targetJndiTemplate"/>
        <property name="jndiName" value="jms/ConnectionFactory"/>
    </bean>
    <bean id="targetDestination" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="targetJndiTemplate"/>
        <property name="jndiName" value="jms/CompanyQueue"/>
    </bean>
    <bean id="taskExecutor" class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">
        <property name="workManagerName" value="java:comp/env/default"/>
        <property name="resourceRef" value="true"/>
    </bean>
    <bean class="org.springframework.jms.listener.SimpleMessageListenerContainer">
        <property name="connectionFactory" ref="targetConnectionFactory"/>
        <property name="destination" ref="targetDestination"/>
        <property name="messageListener" ref="receiver"/>
        <property name="taskExecutor" ref="taskExecutor"/>
    </bean>
    <bean id="receiver" class="model.logic.JMSReceiver"/>
</beans>

in which the receiver bean looks as follows

package model.logic;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

public class JMSReceiver implements MessageListener {
    public JMSReceiver() {
    }

    public void onMessage(Message message) {
        TextMessage text = (TextMessage)message;
        try {
            message.acknowledge();
            System.out.println("received the following message: " + text.getText());
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

We deploy the sender to the AdminServer and the receiver to the cluster (the server set-up can be found here). To deploy the application we add a web.xml with the following contents

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
           version="3.0">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-config.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- default weblogic work manager -->
    <resource-ref>
        <res-ref-name>default</res-ref-name>
        <res-type>commonj.work.WorkManager</res-type>
        <res-auth>Container</res-auth>
        <res-sharing-scope>Shareable</res-sharing-scope>
    </resource-ref>
    <!-- default weblogic timer manager -->
    <resource-ref>
        <res-ref-name>tm/default</res-ref-name>
        <res-type>commonj.timers.TimerManager</res-type>
        <res-auth>Container</res-auth>
        <res-sharing-scope>Shareable</res-sharing-scope>
    </resource-ref>
    <servlet>
        <servlet-name>TestServlet</servlet-name>
        <servlet-class>test.TestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>TestServlet</servlet-name>
        <url-pattern>/testservlet</url-pattern>
    </servlet-mapping>
</web-app>

What happens when the applications run is that a JMS producer (sender) is connected to the SAF environment on the AdminServer. The JMS producer sends messages every 30 seconds, which is configured by using a commonj timer manager. The message send to the SAF queue is being forwarded to the jms/CompanyQueue (a distributed queue) to which a JMS consumer (receiver) is listening by using a SimpleMessageListenerContainer that is coupled to a commonj work manager in order to make sure the thread spawned by the listener is managed by the WebLogic Server. In the logging the following is observed

Logging server1 in the cluster
Apr 16, 2012 11:41:02 AM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization started
Apr 16, 2012 11:41:02 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.web.context.support.XmlWebApplicationContext@1e3c6703: display name [Root WebApplicationContext]; startup date [Mon Apr 16 11:41:02 CEST 2012]; root of context hierarchy
Apr 16, 2012 11:41:03 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring-config.xml]
Apr 16, 2012 11:41:03 AM org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org.springframework.web.context.support.XmlWebApplicationContext@1e3c6703]: org.springframework.beans.factory.support.DefaultListableBeanFactory@1e4efd06
Apr 16, 2012 11:41:03 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1e4efd06: defining beans [sourceJndiTemplate,targetJndiTemplate,sourceConnectionFactory,sourceDestination,sourceJmsTemplate,targetConnectionFactory,targetDestination,taskExecutor,timerListener,timerFactory,org.springframework.jms.listener.SimpleMessageListenerContainer#0,sender,receiver]; root of factory hierarchy
Apr 16, 2012 11:41:03 AM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization completed in 842 ms
received the following message: d8nv7v6vgm5j
received the following message: 1be4omcwwiy61
received the following message: 19y6wh44hora6
received the following message: ha5hp6gaw6ql
received the following message: xercuxsl5qwf
received the following message: 1vvx5lptldi8r
received the following message: 1cgsdl10dkokz
received the following message: qfmd6v14tbb6
received the following message: 53hsnn8dfmor
received the following message: 8uaecn6919mi
received the following message: 8i93wuglm4lj
received the following message: 11d5bkqc5vdnq
received the following message: wc9hpcqmzjj9
received the following message: 17zj64mnvj7d9
received the following message: 1dt5g68vv9d50
received the following message: 13ch0ee5ofrzb
received the following message: 121t0btwasrqs
received the following message: 1lr8qb6il7nac
received the following message: 1l6lm4lge9tjx
received the following message: 15bgb2y3qzxl8
received the following message: vlryb3s3cn1o
received the following message: 189ahnkk5me1n
received the following message: 1wlhom58c3u01

Logging server2 in the cluster
Apr 16, 2012 11:41:02 AM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization started
Apr 16, 2012 11:41:02 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.web.context.support.XmlWebApplicationContext@1e9e9ebc: display name [Root WebApplicationContext]; startup date [Mon Apr 16 11:41:02 CEST 2012]; root of context hierarchy
Apr 16, 2012 11:41:03 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring-config.xml]
Apr 16, 2012 11:41:03 AM org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org.springframework.web.context.support.XmlWebApplicationContext@1e9e9ebc]: org.springframework.beans.factory.support.DefaultListableBeanFactory@1ec29f17
Apr 16, 2012 11:41:03 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1ec29f17: defining beans [sourceJndiTemplate,targetJndiTemplate,sourceConnectionFactory,sourceDestination,sourceJmsTemplate,targetConnectionFactory,targetDestination,taskExecutor,timerListener,timerFactory,org.springframework.jms.listener.SimpleMessageListenerContainer#0,sender,receiver]; root of factory hierarchy
Apr 16, 2012 11:41:03 AM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization completed in 686 ms
received the following message: 1uwivfp2ngq1t
received the following message: bo4z7iakwqqv
received the following message: 1sdrelhucxxed
received the following message: 99xztxrc3f9f
received the following message: 1u8ej4ls0avqt
received the following message: hhkpei2bqyaw
received the following message: 2nid8k122rnd
received the following message: m2n72h6ajiao
received the following message: 1wpp89uiqttrw
received the following message: 18ecmmhgmmheu
received the following message: 1neja8ptey39a
received the following message: 1iu5em4cknpaa
received the following message: p89q16c2npbp
received the following message: 13gx5jqyzh57n
received the following message: 6lcjw5vjpttp
received the following message: 74wvvr4ey35s
received the following message: 1mcnjxzy2xp6f
received the following message: 12d6ybdpmi2wp

The extra messages in server1 are there because when running Spring as a client instead of being deployed to the WebLogic cluster, the receiver is only registered to one queue in the distributed queue. To test the set-up (without the timer manager and work manager configuration and) without deploying the application to WebLogic we can use

package model.test;

import model.logic.JMSSender;
import model.utils.SpringUtilities;

public class JMSTest {

    public static void main(String[] args) {
        JMSSender jmsSender = SpringUtilities.getJMSSender();

        while (true) {
            jmsSender.sendMessage();
            System.out.println("done sending message");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Performance considerations

The following documents provide information on various methods to improve performance:

Another tuning parameter to consider is the chunk size. A chunk is a unit of memory that the WebLogic Server network layer, both on the client and server side, uses to read data from and write data to sockets. To reduce memory allocation costs, a server instance maintains a pool of these chunks. For applications that handle large amounts of data per request, increasing the value on both the client and server sides can boost performance. The default chunk size is about 4K. Use the following properties to tune the chunk size and the chunk pool size:

  • weblogic.Chunksize – sets the size of a chunk (in bytes). The primary situation in which this may need to be increased is if request sizes are large. It should be set to values that are multiples of the network’s maximum transfer unit (MTU), after subtracting from the value any Ethernet or TCP header sizes. Set this parameter to the same value on the client and server.
  • weblogic.utils.io.chunkpoolsize – sets the maximum size of the chunk pool. The default value is 2048. The value may need to be increased if the server starts to allocate and discard chunks in steady state. To determine if the value needs to be increased, monitor the CPU profile or use a memory/ heap profiler for call stacks invoking the constructor weblogic.utils.io.Chunk.
  • weblogic.PartitionSize – sets the number of pool partitions used (default is 4). The chunk pool can be a source of significant lock contention as each request to access to the pool must be synchronized. Partitioning the thread pool spreads the potential for contention over more than one partition.

For example, we can set the chunksize by using -Dweblogic.Chunksize=65536 on the command-line.

References

[1] Configuring and Managing JMS for WebLogic Server.
[2] Configuring and Managing the Messaging Bridge for WebLogic Server.
[3] Configuring and Managing Store-and-Forward for WebLogic Server.
[4] Performance and Tuning for WebLogic Server.


Spring and GlassFish JMS

In this post we set-up a GlassFish Server environment that includes a JMS configuration that will be used by a Spring client. First, we look at some considerations when developing a client that uses JMS. Next, we look at the classloading, i.e., the classes needed in order for Spring to communicate with GlassFish and obtain JMS resources from JNDI. Finally, we show the configuration needed in Spring and test the set-up.

Some notes up front

The Java Messaging Specification was developed to abstract access to message-oriented middleware systems. A client that writes JMS code should be portable to any provider that implements this specification. If code portability is important, be sure to do the following in developing clients:

  • Make sure the code does not depend on extensions or features that are specific to Message Queue.
  • Look up, using JNDI, (rather than instantiate) administered objects for connection factories and destinations.

Another point to consider when developing a client is to use threads effectively, i.e., we need to balance performance, throughput, and resource needs. To do this, we need to understand JMS restrictions on thread usage, what threads Message Queue allocates for itself, and the architecture of the applications. The Java Messaging Specification mandates that a session not be operated on by more than one thread at a time. This leads to the following restrictions:

  • A session may not have an asynchronous consumer and a synchronous consumer.
  • A session that has an asynchronous consumer can only produce messages from within the onMessage() method (the message listener). The only call that we can make outside the message listener is to close the session.
  • A session may include any number of synchronous consumers, any number of producers, and any combination of the two. That is, the single-thread requirement cannot be violated by these combinations. However, performance may suffer.

The system does not enforce the requirement that a session be single threaded. If the client application violates this requirement, we will get a JMSIllegalState exception or unexpected results. When the Message Queue client runtime creates a connection, it creates two threads: one for consuming messages from the socket, and one to manage the flow of messages for the connection. In addition, the client runtime creates a thread for each client session. Thus, at a minimum, for a connection using one session, three threads are created. For a connection using three sessions, five threads are created, and so on. Managing threads in a JMS application often involves trade-offs between performance and throughput. Weigh the following considerations when dealing with threading issues. When we create several asynchronous message consumers in the same session, messages are delivered serially by the session thread to these consumers. Sharing a session among several message consumers might starve some consumers of messages while inundating other consumers. If the message rate across these consumers is high enough to cause an imbalance, we might want to separate the consumers into different sessions. To determine whether message flow is unbalanced, we can monitor destinations to see the rate of messages coming in. We can reduce the number of threads allocated to the client application by using fewer connections and fewer sessions. However, doing this might slow the application’s throughput. We might be able to use certain JVM runtime options to improve thread memory usage and performance.

A client application running in a JVM needs enough memory to accommodate messages that flow in from the network as well as messages the client creates. If the client gets OutOfMemoryError errors, chances are that not enough memory was provided to handle the size or the number of messages being consumed or produced. The client might need more than the default JVM heap space. Consider the following guidelines:

  • Evaluate the normal and peak system memory footprints when sizing heap space.
  • Adjust the heap size settings accordingly (the best size for the heap space depends on both the operating system and the JDK release).

In general, for better manageability, we can break large messages into smaller parts, and use sequencing to ensure that the partial messages sent are concatenated properly. We can also use a Message Queue JMS feature to compress the body of a message. Compression only affects the message body; the message header and properties are not compressed. Although message compression has been added to improve performance, such benefit is not guaranteed. Benefits vary with the size and format of messages, the number of consumers, network bandwidth, and CPU performance. For example, the cost of compression and decompression might be higher than the time saved in sending and receiving a compressed message. This is especially true when sending small messages in a high-speed network. On the other hand, applications that publish large messages to many consumers or who publish in a slow network environment, might improve system performance by compressing messages.

Persistent messages guarantee message delivery in case of broker failure. The broker stores these message in a persistent store until all intended consumers acknowledge that they have consumed the message. Broker processing of persistent messages is slower than for nonpersistent messages for the following reasons:

  • A broker must reliably store a persistent message so that it will not be lost should the broker fail.
  • The broker must confirm receipt of each persistent message it receives. Delivery to the broker is guaranteed once the method producing the message returns without an exception.
  • Depending on the client acknowledgment mode, the broker might need to confirm a consuming client’s acknowledgment of a persistent message.

A transaction guarantees that all messages produced in a transacted session and all messages consumed in a transacted session will be either processed or not processed (rolled back) as a unit. A message produced or acknowledged in a transacted session is slower than in a non-transacted session for the following reasons:

  • Additional information must be stored with each produced message.
  • In some situations, messages in a transaction are stored when normally they would not be. For example, a persistent message delivered to a topic destination with no subscriptions would normally be deleted, however, at the time the transaction is begun, information about subscriptions is not available.
  • Information on the consumption and acknowledgment of messages within a transaction must be stored and processed when the transaction is committed.

Other than using transactions, we can ensure reliable delivery by having the client acknowledge receiving a message. The messaging provider can sort messages according to criteria specified in the message selector associated with a consumer and deliver to that consumer only those messages whose property value matches the message selector. Creating consumers with selectors lowers performance (as compared to using multiple destinations) because additional processing is required to handle each message. When a selector is used, it must be parsed so that it can be matched against future messages. Additionally, the message properties of each message must be retrieved and compared against the selector as each message is routed. However, using selectors provides more flexibility in a messaging application and may lower resource requirements at the expense of speed.

Message size affects performance because more data must be passed from producing client to broker and from broker to consuming client, and because for persistent messages a larger message must be stored. However, by batching smaller messages into a single message, the routing and processing of individual messages can be minimized, providing an overall performance gain. In this case, information about the state of individual messages is lost. JMS supports five message body types, shown below roughly in the order of complexity:

  • Bytes: Contains a set of bytes in a format determined by the application.
  • Text: Is a java.lang.String.
  • Stream: Contains a stream of Java primitive values.
  • Map: Contains a set of name-and-value pairs.
  • Object: Contains a Java serialized object.

While, in general, the message type is dictated by the needs of an application, the more complicated types (map and object) carry a performance cost – the expense of serializing and deserializing the data. The performance cost depends on how simple or how complicated the data is.

Developing the JMS client with Spring

When using GlassFish JMS in a Spring client we need the right classes on the class path. The gf-client.jar contains all the necessary references, i.e., the MANIFEST.MF contained in the jar file looks as follows

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.6.5
Created-By: Apache Maven
Archiver-Version: Plexus Archiver
Built-By: java_re
Build-Jdk: 1.6.0_10
Package: org.glassfish.appclient.client.acc
Main-Class: org.glassfish.appclient.client.AppClientFacade
GlassFish-ServerExcluded: true
PreMain-Class: org.glassfish.appclient.client.acc.agent.AppClientContainerAgent
Class-Path: ../modules/jtype.jar ../modules/tools.jar ../modules/glassfish-corba-asm.jar ../modules/glassfish-corba-codegen.jar ../modules/glassfish-corba-csiv2-idl.jar ../modules/glassfish-corba-internal-api.jar ../modules/glassfish-corba-newtimer.jar ../modules/glassfish-corba-omgapi.jar ../modules/glassfish-corba-orb.jar ../modules/glassfish -corba-orbgeneric.jar ../modules/auto-depends.jar ../modules/config.jar ../modules/config-types.jar ../modules/hk2.jar ../modules/hk2-core.jar ../modules/osgi-adapter.jar ../modules/grizzly-comet.jar ../modules/grizzly-config.jar ../modules/grizzly-framework.jar ../modules/grizzly-http.jar ../modules/grizzly-http-servlet.jar ../modules/grizzly-lzma.jar ../modules/grizzly-portunif.jar ../modules/grizzly-rcm.jar ../modules/grizzly-utils.jar ../modules/grizzly-websockets.jar ../modules/javax.mail.jar ../modules/pkg-client.jar ../modules/jaxb-osgi.jar ../modules/activation.jar ../modules/el-api.jar ../modules/jaxr-api-osgi.jar ../modules/jaxrpc-api-osgi.jar ../modules/endorsed/jaxb-api-osgi.jar ../modules/stax-api.jar ../modules/junit.jar ../modules/stax2-api.jar ../modules/woodstox-core-asl.jar ../modules/javax.persistence.jar ../modules/org.eclipse.persistence.antlr.jar ../modules/org.eclipse.persistence.asm.jar ../modules/org.eclipse.persistence.core.jar ../modules/org.eclipse.persistence.jpa.jar ../modules/org.eclipse.persistence.jpa.modelgen.jar ../modules/org.eclipse.persistence.oracle.jar ../modules/endorsed/javax.annotation.jar ../modules/javax.ejb.jar ../modules/javax.enterprise.deploy.jar ../modules/javax.jms.jar ../modules/javax.management.j2ee.jar ../modules/javax.resource.jar ../modules/javax.security.auth.message.jar ../modules/javax.security.jacc.jar ../modules/javax.servlet.jar ../modules/javax.servlet.jsp.jar ../modules/javax.transaction.jar ../modules/simple-glassfish-api.jar ../modules/admin-core.jar ../modules/admin-util.jar ../modules/config-api.jar ../modules/monitoring-core.jar ../modules/acc-config.jar ../modules/gf-client-module.jar ../modules/gms-bootstrap.jar ../modules/amx-core.jar ../modules/amx-j2ee.jar ../modules/annotation-framework.jar ../modules/common-util.jar ../modules/container-common.jar ../modules/glassfish-api.jar ../modules/glassfish-ee-api.jar ../modules/glassfish-naming.jar ../modules/internal-api.jar ../modules/scattered-archive-api.jar ../modules/stats77.jar ../modules/connectors-inbound-runtime.jar ../modules/connectors-internal-api.jar ../modules/connectors-runtime.jar ../modules/work-management.jar ../modules/glassfish.jar ../modules/kernel.jar ../modules/logging.jar ../modules/deployment-common.jar ../modules/deployment-javaee-core.jar ../modules/dol.jar ../modules/ejb-container.jar ../modules/ejb-internal-api.jar ../modules/ldapbp-repackaged.jar ../modules/libpam4j-repackaged.jar ../modules/management-api.jar ../modules/flashlight-framework.jar ../modules/gmbal.jar ../modules/ha-api.jar ../modules/class-model.jar ../modules/asm-a ll-repackaged.jar ../modules/bean-validator.jar ../modules/jms-core.jar ../modules/endorsed/webservices-api-osgi.jar ../modules/webservices-extra-jdk-packages.jar ../modules/webservices-osgi.jar ../modules/orb-connector.jar ../modules/orb-iiop.jar ../modules/eclipselink-wrapper.pom ../modules/jpa-connector.jar ../modules/persistence-common.jar ../modules/cmp-internal-api.jar ../modules/appclient.security.jar ../modules/ejb.security.jar ../modules/jaspic.provider.framework.jar ../modules/security.jar ../modules/ssl-impl.jar ../modules/websecurity.jar ../modules/webservices.security.jar ../modules/jta.jar ../modules/jts.jar ../modules/transaction-internal-api.jar ../modules/el-impl.jar ../modules/jsp-impl.jar ../modules/war-util.jar ../modules/web-cli.jar ../modules/web-core.jar ../modules/web-embed-api.jar ../modules/web-glue.jar ../modules/web-gui-plugin-common.jar ../modules/web-naming.jar ../modules/jsr109-impl.jar ../modules/mimepull.jar ../modules/tiger-types.jar ../modules/shoal-gms-api.jar ../../mq/lib/imq.jar ../ ../mq/lib/imqadmin.jar ../../mq/lib/imqutil.jar ../../mq/lib/fscontext.jar ../lib/install/applications/jmsra/imqjmsra.jar ../lib/install/applications/__ds_jdbc_ra/__ds_jdbc_ra.jar ../lib/install/applications/__cp_jdbc_ra/__cp_jdbc_ra.jar ../lib/install/applications/__xa_jdbc_ra/__xa_jdbc_ra.jar ../lib/install/applications/__dm_jdbc_ra/__dm_jdbc_ra.jar ../../javadb/lib/derby.jar ../../javadb/lib/derbyclient.jar ../../javadb/lib/derbynet.jar ../../javadb/lib/derbytools.jar ../../javadb/lib/derbyrun.jar ../lib/install/applications/jaxr-ra/jaxr-ra.jar ../modules/aixporting-repackaged.jar
GlassFish-Conditional-Additions: ../modules/aixporting-repackaged.jar

which is of course quite a lot to have on the classpath when we just want to use JMS. Note that it also means we have to install GlassFish on the client. So naturally you start to look for alternative ways. To see if we can obtain an object from a GlassFish server by using JNDI, we can create a little test class, for example,

package model.test;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Properties;

public class JMSTest {

    public static void main(String[] args) {
        Properties props = new Properties();
        props.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");
        props.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming");
        props.setProperty("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
        props.setProperty("org.omg.CORBA.ORBInitialHost", "192.168.1.50");
        props.setProperty("org.omg.CORBA.ORBInitialPort", "3700");

        try {
            Context context = new InitialContext(props);
            System.out.println(context);
            System.out.println(context.lookup("jms/ConnectionFactory"));
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }
}

When running this class we of course miss classes on the class path. To find which jar contains the missing class we can use

#!/bin/sh

PATH=${PATH}:/home/oracle/jdk1.6.0_31/bin
export PATH

LOOK_FOR="org/glassfish/api/admin/ProcessEnvironment$ProcessType"
export LOOK_FOR

for i in `find /home/oracle/glassfish3/glassfish/modules -name "*jar"`
do
	jar tvf $i | grep $LOOK_FOR > /dev/null
	if [ $? == 0 ]
	then
		echo "==> Found \"$LOOK_FOR\" in $i"
	fi
done

Here the LOOK_FOR variable is set to the value for the missing class and the first parameter in the find command is the path in which to look. After a while we get to a collection of these classes

auto-depends.jar
common-util.jar
glassfish-api.jar
glassfish-corba-internal-api.jar
glassfish-naming.jar
hk2-core.jar
internal-api.jar

and run into the following exception

Caused by: javax.naming.NamingException: Unable to acquire SerialContextProvider for SerialContext[myEnv={java.naming.provider.url=iiop://192.168.1.50:3700, java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory, java.naming.factory.url.pkgs=com.sun.enterprise.naming, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl} [Root exception is java.lang.NullPointerException]
	at com.sun.enterprise.naming.impl.SerialContext.getProvider(SerialContext.java:352)
	at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:504)
	... 8 more
Caused by: java.lang.NullPointerException
	at com.sun.enterprise.naming.impl.SerialContext.getORB(SerialContext.java:365)
	at com.sun.enterprise.naming.impl.SerialContext.getProviderCacheKey(SerialContext.java:372)
	at com.sun.enterprise.naming.impl.SerialContext.getRemoteProvider(SerialContext.java:402)
	at com.sun.enterprise.naming.impl.SerialContext.getProvider(SerialContext.java:347)
	... 9 more

Now what? You go for the gf-client.jar and install GlassFish on the client. Not the nicest of solutions but one that works. The gf-client.jar file is located in the ${GLASS_HOME}/glassfish/lib directory. With gf-client.jar on the class path we get the following output when running the test

javax.naming.InitialContext@682bc3f5
Apr 12, 2012 4:59:02 PM org.hibernate.validator.util.Version <clinit>
INFO: Hibernate Validator 4.1.0.Final
Apr 12, 2012 4:59:02 PM org.hibernate.validator.engine.resolver.DefaultTraversableResolver detectJPA
INFO: Instantiated an instance of org.hibernate.validator.engine.resolver.JPATraversableResolver.
Apr 12, 2012 4:59:02 PM com.sun.messaging.jms.ra.ResourceAdapter start
INFO: MQJMSRA_RA1101: GlassFish MQ JMS Resource Adapter: Version:  4.5.1  (Build 3-b) Compile:  Tue Jun 21 16:31:32 PDT 2011
Apr 12, 2012 4:59:02 PM com.sun.messaging.jms.ra.ResourceAdapter start
INFO: MQJMSRA_RA1101: GlassFish MQ JMS Resource Adapter starting: broker is REMOTE, connection mode is TCP
Apr 12, 2012 4:59:02 PM com.sun.messaging.jms.ra.ResourceAdapter start
INFO: MQJMSRA_RA1101: GlassFish MQ JMS Resource Adapter Started:REMOTE
com.sun.messaging.jms.ra.ConnectionFactoryAdapter@61672c01

Next we need to configure Spring

<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 id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
        <property name="environment">
            <props>
                <prop key="java.naming.factory.initial">com.sun.enterprise.naming.SerialInitContextFactory</prop>
                <prop key="java.naming.factory.url.pkgs">com.sun.enterprise.naming</prop>
                <prop key="java.naming.factory.state">com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl</prop>
                <prop key="org.omg.CORBA.ORBInitialHost">192.168.1.50</prop>
                <prop key="org.omg.CORBA.ORBInitialPort">3700</prop>
            </props>
        </property>
    </bean>
    <bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="jndiTemplate"/>
        <property name="jndiName" value="jms/ConnectionFactory"/>
    </bean>
    <bean id="destination" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="jndiTemplate"/>
        <property name="jndiName" value="jms/CompanyQueue"/>
    </bean>
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="defaultDestination" ref="destination"/>
    </bean>
    <bean class="org.springframework.jms.listener.SimpleMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="destination" ref="destination"/>
        <property name="messageListener" ref="receiver"/>
    </bean>
    <bean id="sender" class="model.logic.JMSSender">
        <property name="jmsTemplate" ref="jmsTemplate"/>
    </bean>
    <bean id="receiver" class="model.logic.JMSReceiver"/>
</beans>

The classes JMSSender and JMSReceiver can be found in the post WebLogic JMS Clustering and Spring. The post Fun with GlassFish shows the steps involved in how to create the JMS resources (connection factory and queue). To test the set-up we can use

package model.test;

import model.logic.JMSSender;
import model.utils.SpringUtilities;

public class JMSTest {

    public static void main(String[] args) {
        JMSSender jmsSender = SpringUtilities.getJMSSender();
        jmsSender.sendMessage();
        System.out.println("done sending message");
    }
}

which leads to the following output

Apr 12, 2012 5:30:45 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@78b5f53a: display name [org.springframework.context.support.ClassPathXmlApplicationContext@78b5f53a]; startup date [Thu Apr 12 17:30:45 CEST 2012]; root of context hierarchy
Apr 12, 2012 5:30:45 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring-config.xml]
Apr 12, 2012 5:30:45 PM org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@78b5f53a]: org.springframework.beans.factory.support.DefaultListableBeanFactory@21b64e6a
Apr 12, 2012 5:30:45 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@21b64e6a: defining beans [jndiTemplate,connectionFactory,destination,jmsTemplate,org.springframework.jms.listener.SimpleMessageListenerContainer#0,sender,receiver]; root of factory hierarchy
Apr 12, 2012 5:30:49 PM org.hibernate.validator.util.Version <clinit>
INFO: Hibernate Validator 4.1.0.Final
Apr 12, 2012 5:30:49 PM org.hibernate.validator.engine.resolver.DefaultTraversableResolver detectJPA
INFO: Instantiated an instance of org.hibernate.validator.engine.resolver.JPATraversableResolver.
Apr 12, 2012 5:30:49 PM com.sun.messaging.jms.ra.ResourceAdapter start
INFO: MQJMSRA_RA1101: GlassFish MQ JMS Resource Adapter: Version:  4.5.1  (Build 3-b) Compile:  Tue Jun 21 16:31:32 PDT 2011
Apr 12, 2012 5:30:49 PM com.sun.messaging.jms.ra.ResourceAdapter start
INFO: MQJMSRA_RA1101: GlassFish MQ JMS Resource Adapter starting: broker is REMOTE, connection mode is TCP
Apr 12, 2012 5:30:49 PM com.sun.messaging.jms.ra.ResourceAdapter start
INFO: MQJMSRA_RA1101: GlassFish MQ JMS Resource Adapter Started:REMOTE
received the following message: 8dxgbdo4u4ee
done sending message

References

[1] GlassFish Server Documentation.


WebLogic JMS Clustering and Spring

In this post we set-up a WebLogic cluster that includes a JMS environment, which will be used by Spring. A distributed queue will be used in order to load balance the JMS message processing.

Create domain

To create our domain, we are going to use WLST. The following script, creates the domain in production mode, disables hostname verification, creates two managed server that are clustered and creates the artifacts needed to run the application.

beahome = '/home/oracle/weblogic12.1.1';
pathseparator = '/';
adminusername = 'weblogic';
adminpassword = 'magic12c';
adminservername='AdminServer';
adminserverurl='t3://axis-into-ict.nl:7001';
domainname = 'base_domain';
domaindirectory = beahome + pathseparator + 'configuration' + pathseparator + 'domains' + pathseparator + domainname;
domaintemplate = beahome + pathseparator + 'wlserver_12.1' + pathseparator + 'common' + pathseparator + 'templates' + pathseparator + 'domains' + pathseparator + 'wls.jar';
jvmdirectory = '/home/oracle/jrockit-jdk1.6.0_29-R28.2.2-4.1.0';

print 'CREATE DOMAIN';
readTemplate(domaintemplate);
setOption('DomainName', domainname);
setOption('OverwriteDomain', 'true');
setOption('ServerStartMode', 'prod');
cd('/Security/' + domainname + '/User/weblogic');
cmo.setName(adminusername);
cmo.setUserPassword(adminpassword);
cd('/');
writeDomain(domaindirectory);

print 'START ADMIN SERVER';
startServer(adminservername, domainname, adminserverurl, adminusername, adminpassword, domaindirectory);

print 'CONNECT TO ADMIN SERVER';
connect(adminusername, adminpassword, adminserverurl);

print 'START EDIT MODE';
edit();
startEdit();

print 'DISABLE HOSTNAME VERIFICATION';
cd('/Servers/' + adminservername + '/SSL/' + adminservername);
cmo.setHostnameVerificationIgnored(true);
cmo.setHostnameVerifier(None);
cmo.setTwoWaySSLEnabled(false);
cmo.setClientCertificateEnforced(false);
cd('/');

print 'SAVE AND ACTIVATE CHANGES';
save();
activate(block='true');

print 'SHUTDOWN THE ADMIN SERVER';
shutdown(block='true');

print 'START ADMIN SERVER';
startServer(adminservername, domainname, adminserverurl, adminusername, adminpassword, domaindirectory);

print 'CONNECT TO ADMIN SERVER';
connect(adminusername, adminpassword, adminserverurl);

print 'START EDIT MODE';
edit();
startEdit();

print 'CREATE MACHINE: machine1';
machine1 = cmo.createUnixMachine('machine1');
machine1.setPostBindUIDEnabled(true);
machine1.setPostBindUID('oracle');
machine1.getNodeManager().setListenAddress('axis-into-ict.nl');
machine1.getNodeManager().setNMType('ssl');

print 'CREATE CLUSTER: CLUSTER';
cluster = cmo.createCluster('cluster');
cluster.setClusterMessagingMode('unicast');

print 'CREATE MANAGED SERVER: server1';
server1 = cmo.createServer('server1');
server1.setListenPort(9001);
server1.setListenAddress('axis-into-ict.nl');
server1.setAutoRestart(true);
server1.setAutoKillIfFailed(true);
server1.setRestartMax(2);
server1.setRestartDelaySeconds(10);
server1.getServerStart().setJavaHome(jvmdirectory);
server1.getServerStart().setJavaVendor('Oracle');
server1.getServerStart().setArguments('-jrockit -Xms512m -Xmx512m -Xgc:throughput');

print 'CREATE MANAGED SERVER: server2';
server2 = cmo.createServer('server2');
server2.setListenPort(9002);
server2.setListenAddress('axis-into-ict.nl');
server2.setAutoRestart(true);
server2.setAutoKillIfFailed(true);
server2.setRestartMax(2);
server2.setRestartDelaySeconds(10);
server2.getServerStart().setJavaHome(jvmdirectory);
server2.getServerStart().setJavaVendor('Oracle');
server2.getServerStart().setArguments('-jrockit -Xms512m -Xmx512m -Xgc:throughput');

print 'ADD MANAGED SERVERS TO CLUSTER';
server1.setCluster(cluster);
server2.setCluster(cluster);

print 'ADD MANAGED SERVERS TO MACHINE';
server1.setMachine(machine1);
server2.setMachine(machine2);

print 'SAVE AND ACTIVATE CHANGES';
save();
activate(block='true');

print 'START EDIT MODE';
startEdit();

print 'CREATE FILESTORE FOR SERVER1';
filestore1 = cmo.createFileStore('FileStore1');
filestore1.setDirectory(beahome + pathseparator + 'configuration' + pathseparator + 'applications' + pathseparator + domainname);
targets = filestore1.getTargets();
targets.append(server1);
filestore1.setTargets(targets);

print 'CREATE JMS SERVER FOR SERVER1';
jmsserver1 = cmo.createJMSServer('JMSServer1');
jmsserver1.setPersistentStore(filestore1);
jmsserver1.setTargets(targets);

targets.remove(server1);
targets.append(server2);

print 'CREATE FILESTORE FOR SERVER2';
filestore2 = cmo.createFileStore('FileStore2');
filestore2.setDirectory(beahome + pathseparator + 'configuration' + pathseparator + 'applications' + pathseparator + domainname);
filestore2.setTargets(targets);

print 'CREATE JMS SERVER FOR SERVER2';
jmsserver2 = cmo.createJMSServer('JMSServer2');
jmsserver2.setPersistentStore(filestore2);
jmsserver2.setTargets(targets);

targets.remove(server2);
targets.append(cluster);

print 'CREATE JMS SYSTEM MODULE';
module = cmo.createJMSSystemResource('SystemModule');
module.setTargets(targets);

print 'CREATE SUBDEPLOYMENT';
module.createSubDeployment('SubDeployment');
cd('/JMSSystemResources/SystemModule/SubDeployments/SubDeployment');
set('Targets',jarray.array([ObjectName('com.bea:Name=JMSServer1,Type=JMSServer'), ObjectName('com.bea:Name=JMSServer2,Type=JMSServer')], ObjectName));
cd('/');

resource = module.getJMSResource();

print 'CREATE CONNECTION FACTORY';
resource.createConnectionFactory('ConnectionFactory');
connectionfactory = resource.lookupConnectionFactory('ConnectionFactory');
connectionfactory.setJNDIName('jms/ConnectionFactory');
connectionfactory.setDefaultTargetingEnabled(true);
connectionfactory.getTransactionParams().setTransactionTimeout(3600);
connectionfactory.getTransactionParams().setXAConnectionFactoryEnabled(true);

print 'CREATE UNIFORM DISTRIBUTED QUEUE';
resource.createUniformDistributedQueue('DistributedQueue');
distributedqueue = resource.lookupUniformDistributedQueue('DistributedQueue');
distributedqueue.setJNDIName('jms/CompanyQueue');
distributedqueue.setLoadBalancingPolicy('Round-Robin');
distributedqueue.setSubDeploymentName('SubDeployment');

print 'SAVE AND ACTIVATE CHANGES';
save();
activate(block='true');

print 'SHUTDOWN THE ADMIN SERVER';
shutdown(block='true');

Application

The Spring configuration file looks as follows

<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 id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
        <property name="environment">
            <props>
                <prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
                <prop key="java.naming.provider.url">t3://192.168.1.50:9001,192.168.1.50:9002</prop>
            </props>
        </property>
    </bean>
    <bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="jndiTemplate"/>
        <property name="jndiName" value="jms/ConnectionFactory"/>
    </bean>
    <bean id="destination" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="jndiTemplate"/>
        <property name="jndiName" value="jms/CompanyQueue"/>
    </bean>
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="defaultDestination" ref="destination"/>
    </bean>
    <bean id="taskExecutor" class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">
        <property name="workManagerName" value="java:comp/env/default"/>
        <property name="resourceRef" value="true"/>
    </bean>
    <bean id="timerListener" class="org.springframework.scheduling.commonj.ScheduledTimerListener">
        <property name="delay" value="10000"/>
        <property name="period" value="30000"/>
        <property name="runnable" ref="sender"/>
    </bean>
    <bean id="timerFactory" class="org.springframework.scheduling.commonj.TimerManagerFactoryBean">
        <property name="timerManagerName" value="java:comp/env/tm/default"/>
        <property name="resourceRef" value="true"/>
        <property name="scheduledTimerListeners">
            <list>
                <ref bean="timerListener"/>
            </list>
        </property>
    </bean>
    <bean class="org.springframework.jms.listener.SimpleMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="destination" ref="destination"/>
        <property name="messageListener" ref="receiver"/>
        <property name="taskExecutor" ref="taskExecutor"/>
    </bean>
    <bean id="sender" class="model.logic.JMSSender">
        <property name="jmsTemplate" ref="jmsTemplate"/>
    </bean>
    <bean id="receiver" class="model.logic.JMSReceiver"/>
</beans>

Here, we use the WebLogic TimerManager to send messages every 30 seconds to the distributed queue. The messages are picked up by the SimpleMessageListenerContainer, for which the threads are managed by the default WebLogic WorkManager. The JMSSender looks as follows

package model.logic;

import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import java.util.Random;

public class JMSSender implements Runnable {

    private Random generator = new Random();
    private JmsTemplate jmsTemplate;

    public JMSSender() {
    }

    public JmsTemplate getJmsTemplate() {
        return jmsTemplate;
    }

    public void setJmsTemplate(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    public void sendMessage() {
        getJmsTemplate().send(new MessageCreator(){
            public Message createMessage(Session session) throws JMSException {
                TextMessage message = session.createTextMessage();
                message.setText(Long.toString(Math.abs(generator.nextLong()), 36));
                return message;
            }
        });
    }

    public void run() {
        sendMessage();
    }
}

and JMSReceiver looks as follows

package model.logic;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

public class JMSReceiver implements MessageListener {
    public JMSReceiver() {
    }

    public void onMessage(Message message) {
        TextMessage text = (TextMessage)message;
        try {
            message.acknowledge();
            System.out.println("received the following message: " + text.getText());
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

Deploy the application. Open the logging of the specific servers to which the application was deployed to check how the messages are balanced between the servers by the distributed queue:

Apr 11, 2012 11:23:15 AM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization started
Apr 11, 2012 11:23:15 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.web.context.support.XmlWebApplicationContext@1ea13672: display name [Root WebApplicationContext]; startup date [Wed Apr 11 11:23:15 CEST 2012]; root of context hierarchy
Apr 11, 2012 11:23:15 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring-config.xml]
Apr 11, 2012 11:23:15 AM org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org.springframework.web.context.support.XmlWebApplicationContext@1ea13672]: org.springframework.beans.factory.support.DefaultListableBeanFactory@1eac97e6
Apr 11, 2012 11:23:15 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1eac97e6: defining beans [jndiTemplate,connectionFactory,destination,jmsTemplate,taskExecutor,timerListener,timerFactory,org.springframework.jms.listener.SimpleMessageListenerContainer#0,sender,receiver]; root of factory hierarchy
Apr 11, 2012 11:23:16 AM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization completed in 503 ms
received the following message: yqd0zvqllt58
received the following message: vnsw07fqhsmt
received the following message: 1secm492wxbhd
received the following message: 132hz54mtxvae
received the following message: 1nerzk2kcq41t
received the following message: orj9cmwyvvm4
received the following message: z7kz7vecuvoj
received the following message: 1elg1cszki0gz
received the following message: f283omdowrmm
received the following message: 4tfqfrek6tlm
received the following message: 1lka0mjnvjway
received the following message: n6uuuepdjqw1
received the following message: jz3rgzfp5myt
received the following message: iwvbwuvkotb2
received the following message: 1px4ymopgu0z4
received the following message: 1dvaf4do8nnb1
received the following message: vij9m5bilbtc
received the following message: 2vetjvvw9t1l
Apr 11, 2012 11:23:15 AM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization started
Apr 11, 2012 11:23:15 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.web.context.support.XmlWebApplicationContext@1e6a873c: display name [Root WebApplicationContext]; startup date [Wed Apr 11 11:23:15 CEST 2012]; root of context hierarchy
Apr 11, 2012 11:23:15 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring-config.xml]
Apr 11, 2012 11:23:15 AM org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org.springframework.web.context.support.XmlWebApplicationContext@1e6a873c]: org.springframework.beans.factory.support.DefaultListableBeanFactory@1e761a31
Apr 11, 2012 11:23:15 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1e761a31: defining beans [jndiTemplate,connectionFactory,destination,jmsTemplate,taskExecutor,timerListener,timerFactory,org.springframework.jms.listener.SimpleMessageListenerContainer#0,sender,receiver]; root of factory hierarchy
Apr 11, 2012 11:23:15 AM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization completed in 520 ms
received the following message: zvbtb316a5w0
received the following message: 1ur1serspbtls
received the following message: 1bcvfhi0f0vs9
received the following message: pfjts61vsryf
received the following message: 1nbp2sq86n1xm
received the following message: 1e6d9szm0sdx7
received the following message: 1juogzbawdyj9
received the following message: 148bbdq1t4mam
received the following message: 1mhaz3f8zzl1t
received the following message: 13hh354hcrf78
received the following message: 8y4n5g11ah5r
received the following message: c9zu7pcorr0r
received the following message: 4q3rgdshqjo9
received the following message: k3y8jygax551
received the following message: 108s63prt2rjl
received the following message: 1qgseev65213l
received the following message: 1utzdoiyw2ynt

By using a distributed queue the message processing load is balanced between the servers to which queue is targetted.

References

[1] WebLogic Server Documentation.


Wicket Spring in Hibernate on WebLogic

In this post we will look at how to set-up an application that uses Wicket, Spring and Hibernate and runs on WebLogic.

We will use the following versions:
- Wicket-1.5.1 (can be downloaded here).
- Spring-3.0.6 (can be downloaded here).
- Hibernate-3.6.7 (can be downloaded here).
- WebLogic-10.3.5 (can be downloaded here).

First, we will create shared libaries. The hibernate-3.6.war shared library has the following contents:

hibernate-3.6
	META-INF
		MANIFEST.MF
	WEB-INF
		lib
			antlr-2.7.6.jar
			commons-collections-3.1.jar
			dom4j-1.6.1.jar
			hibernate3.jar
			hibernate-jpa-2.0-api-1.0.1.Final.jar
			javassist-3.12.0.GA.jar
			jta-1.1.jar
			slf4j-api-1.6.1.jar

in which the MANIFEST.MF contains:

Manifest-Version: 1.0
Created-By: 1.6.0_05 (BEA Systems, Inc.)
Extension-Name: hibernate
Specification-Title: Hibernate Library
Specification-Version: 3.6
Specification-Vendor: Middleware Magic
Implementation-Title: Hibernate Library
Implementation-Version: 3.6.7
Implementation-Vendor: Middleware Magic

The spring-3.0.war shared library has the following contents:

spring-3.0
	META-INF
		MANIFEST.MF
	WEB-INF
		lib
			aopalliance-1.0.jar
			commons-logging-1.0.4.jar
			org.springframework.aop-3.0.6.RELEASE.jar
			org.springframework.asm-3.0.6.RELEASE.jar
			org.springframework.beans-3.0.6.RELEASE.jar
			org.springframework.context-3.0.6.RELEASE.jar
			org.springframework.core-3.0.6.RELEASE.jar
			org.springframework.expression-3.0.6.RELEASE.jar
			org.springframework.jdbc-3.0.6.RELEASE.jar
			org.springframework.orm-3.0.6.RELEASE.jar
			org.springframework.transaction-3.0.6.RELEASE.jar
			org.springframework.web-3.0.6.RELEASE.jar

in which the MANIFEST.MF contains:

Manifest-Version: 1.0
Created-By: 1.6.0_05 (BEA Systems, Inc.)
Extension-Name: spring
Specification-Title: Spring Library
Specification-Version: 3.0
Specification-Vendor: Middleware Magic
Implementation-Title: Spring Library
Implementation-Version: 3.0.6
Implementation-Vendor: Middleware Magic

The wicket-1.5.war shared library has the following contents:

wicket-1.5
	META-INF
		MANIFEST.MF
	WEB-INF
		lib
			log4j-1.2.16.jar
			slf4j-api-1.6.1.jar
			slf4j-log4j12-1.6.1.jar
			wicket-core-1.5.1.jar
			wicket-request-1.5.1.jar
			wicket-spring-1.5.1.jar
			wicket-util-1.5.1.jar

in which the MANIFEST.MF contains:

Manifest-Version: 1.0
Created-By: 1.6.0_05 (BEA Systems, Inc.)
Extension-Name: wicket
Specification-Title: Wicket Library
Specification-Version: 1.5
Specification-Vendor: Middleware Magic
Implementation-Title: Wicket Library
Implementation-Version: 1.5.1
Implementation-Vendor: Middleware Magic

More information about shared libraries is presented here.

The following interface defines the basic basic persistence operations:

package model.logic;

import java.io.Serializable;
import java.util.List;

public interface GenericDAO<T, ID extends Serializable> {
    public T addEntity(T entity);

    public void removeEntity(ID id);

    public void updateEntity(T entity);

    public T findEntity(ID id);

    public List<T> findEntities();
}

When using Spring and Hibernate the interface can be implemented as follows:

package model.logic;

import org.hibernate.criterion.DetachedCriteria;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public abstract class GenericHibernateSpringDAO<T, ID extends Serializable> implements GenericDAO<T, ID> {

    private Class<T> persistentClass;
    private HibernateTemplate hibernateTemplate;

    public GenericHibernateSpringDAO() {
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            System.out.println(parameterizedType.getActualTypeArguments()[0]);
            setPersistentClass((Class<T>) parameterizedType.getActualTypeArguments()[0]);
        } else {
            System.out.println("Not an instance of parameterized type: " + type);
        }
    }

    public Class<T> getPersistentClass() {
        return persistentClass;
    }

    public void setPersistentClass(Class<T> persistentClass) {
        this.persistentClass = persistentClass;
    }

    public HibernateTemplate getHibernateTemplate() {
        return hibernateTemplate;
    }

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

    public T addEntity(T entity) {
        getHibernateTemplate().save(entity);
        return entity;
    }

    public void removeEntity(ID id) {
        getHibernateTemplate().delete(findEntity(id));
    }

    public void updateEntity(T entity) {
        getHibernateTemplate().update(entity);
    }

    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public T findEntity(ID id) {
        return (T) getHibernateTemplate().get(getPersistentClass(), id);
    }

    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public List<T> findEntities() {
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(getPersistentClass());
        return getHibernateTemplate().findByCriteria(detachedCriteria);
    }
}

The interface can be extended for particular entities, for example,

package model.logic;

import model.entities.Department;
import model.utils.RunTimeInfo;

public interface DepartmentDAO extends GenericDAO<Department, Integer> {
    public RunTimeInfo getRuntimeInfo();
}

with the corresponding implementation:

package model.logic;

import model.entities.Department;
import model.utils.JmxUtils;
import model.utils.RunTimeInfo;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

public class DepartmentDAOBean extends GenericHibernateSpringDAO<Department, Integer> implements DepartmentDAO {

    private JmxUtils jmxUtils;

    public DepartmentDAOBean() {
    }

    public JmxUtils getJmxUtils() {
        return jmxUtils;
    }

    public void setJmxUtils(JmxUtils jmxUtils) {
        this.jmxUtils = jmxUtils;
    }

    @Transactional(propagation = Propagation.NEVER)
    public RunTimeInfo getRuntimeInfo() {
        return getJmxUtils().getRunTimeInfomation();
    }
}

The Spring configuration has the following contents:

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
    <bean id="someApplication" class="userinterface.wicket.application.SomeApplication">
        <property name="departmentDAO" ref="departmentDAO"/>
        <property name="employeeDAO" ref="employeeDAO"/>
    </bean>
    <bean id="departmentDAO" class="model.logic.DepartmentDAOBean">
        <property name="hibernateTemplate" ref="hibernateTemplate"/>
        <property name="jmxUtils" ref="jmxUtils"/>
    </bean>
    <bean id="employeeDAO" class="model.logic.EmployeeDAOBean">
        <property name="hibernateTemplate" ref="hibernateTemplate"/>
    </bean>
    <bean id="jmxUtils" class="model.utils.JmxUtils"/>
    <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mappingResources">
            <list>
                <value>model/entities/Department.hbm.xml</value>
                <value>model/entities/Employee.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.current_session_context_class">${hibernate.current_session_context_class}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
            </props>
        </property>
    </bean>
    <jee:jndi-lookup id="dataSource" jndi-name="jdbc/exampleDS" resource-ref="true"/>
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:spring.properties</value>
            </list>
        </property>
    </bean>
    <bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
    <tx:annotation-driven transaction-manager="jtaTransactionManager"/>
</beans>

Here SomeApplication is our global application object for the Wicket application. This global application object is created once per application and remains the same when clustered. These qualities make it a good candidate to act as a service locator for the application. Wicket allows us to provide a custom factory for creating the global application object. One such factory is SpringWebApplicationFactory, that obtains a global application object instance from the spring application context. Wicket keeps the instance of the global application object in a threadlocal variable and provides helper methods in components to obtain an instance. The following shows an example web.xml that configures Wicket:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-config.xml</param-value>
    </context-param>
    <servlet>
        <servlet-name>TestServlet</servlet-name>
        <servlet-class>userinterface.servlets.TestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>TestServlet</servlet-name>
        <url-pattern>/testservlet</url-pattern>
    </servlet-mapping>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <filter>
        <filter-name>wicket.hello</filter-name>
        <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
        <init-param>
            <param-name>applicationFactoryClassName</param-name>
            <param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value>
        </init-param>
        <init-param>
            <param-name>applicationClassName</param-name>
            <param-value>userinterface.wicket.application.SomeApplication</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>wicket.hello</filter-name>
        <url-pattern>/somepage/*</url-pattern>
    </filter-mapping>
    <resource-ref>
        <res-ref-name>jdbc/exampleDS</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>
</web-app>

Here the TestServlet tests the persistence functionality (and also accesses some WebLogic RunTime information, which will be discussed later) and looks as follows:

package userinterface.servlets;

import model.entities.Department;
import model.entities.Employee;
import model.logic.DepartmentDAO;
import model.logic.EmployeeDAO;
import model.utils.*;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

public class TestServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        DepartmentDAO departmentDAO = Utilities.getDepartmentDAO();

        Department newDepartment = new Department();
        newDepartment.setDepartmentNumber(80);
        newDepartment.setDepartmentName("SOMETHING");
        newDepartment.setLocation("SOMEWHERE");
        departmentDAO.addEntity(newDepartment);

        List<Department> departments = departmentDAO.findEntities();

        departmentDAO.removeEntity(80);

        RunTimeInfo runTimeInfo = departmentDAO.getRuntimeInfo();

        EmployeeDAO employeeDAO = Utilities.getEmployeeDAO();
        Employee employee = employeeDAO.findEntity(7100);
        employee.setEmployeeName("SOMEONE");
        employeeDAO.updateEntity(employee);

        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head><title>GenericSpringHibernateServlet</title></head>");
        out.println("<body>");
        if (departments != null) {
            for (Department department : departments) {
                out.println("<p>" + department.toString() + "</p>");
            }
        } else {
            out.println("<p> no departments </p>");
        }

        if (runTimeInfo != null) {
            List<ServerRunTimeInfo> serverRunTimeInfos = runTimeInfo.getServerRunTimeInfos();
            if (serverRunTimeInfos != null && !serverRunTimeInfos.isEmpty()) {
                for (ServerRunTimeInfo serverRunTimeInfo : serverRunTimeInfos) {
                    out.println("<p>" + serverRunTimeInfo.toString() + "</p>");
                }
            }

            List<ApplicationRunTimeInfo> applicationRunTimeInfos = runTimeInfo.getApplicationRunTimeInfos();
            if (applicationRunTimeInfos != null && !applicationRunTimeInfos.isEmpty()) {
                for (ApplicationRunTimeInfo applicationRunTimeInfo : applicationRunTimeInfos) {
                    out.println("<p>" + applicationRunTimeInfo.toString() + "</p>");
                    List<ComponentRunTimeInfo> componentRunTimeInfos = applicationRunTimeInfo.getComponentRunTimeInfos();
                    if (componentRunTimeInfos != null && !componentRunTimeInfos.isEmpty()) {
                        for (ComponentRunTimeInfo componentRunTimeInfo : componentRunTimeInfos) {
                            out.println("<p> - " + componentRunTimeInfo.toString() + "</p>");
                        }
                    }
                }
            }
        }

        if (employee != null) {
            out.println("<p>" + employee.toString() + "</p>");
        } else {
            out.println("<p> no employee </p>");
        }
        out.println("</body></html>");
        out.close();
    }
}

The global application class (for the Wicket application) has the following contents:

package userinterface.wicket.application;

import model.logic.DepartmentDAO;
import model.logic.EmployeeDAO;
import org.apache.wicket.protocol.http.WebApplication;
import userinterface.wicket.pages.SomePage;

public class SomeApplication extends WebApplication {

    private DepartmentDAO departmentDAO;
    private EmployeeDAO employeeDAO;

    public DepartmentDAO getDepartmentDAO() {
        return departmentDAO;
    }

    public void setDepartmentDAO(DepartmentDAO departmentDAO) {
        this.departmentDAO = departmentDAO;
    }

    public EmployeeDAO getEmployeeDAO() {
        return employeeDAO;
    }

    public void setEmployeeDAO(EmployeeDAO employeeDAO) {
        this.employeeDAO = employeeDAO;
    }

    @Override
    public Class getHomePage() {
        return SomePage.class;
    }
}

Here the Wicket home page class looks as follows:

package userinterface.wicket.pages;

import model.entities.Department;
import model.logic.DepartmentDAO;
import model.utils.Utilities;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import userinterface.wicket.application.SomeApplication;

import java.util.List;

public class SomePage extends WebPage {
    public SomePage() {
        DepartmentDAO departmentDAO = ((SomeApplication) getApplication()).getDepartmentDAO();

        List<Department> departments = departmentDAO.findEntities();

        add(new Label("message", "DEPARTMENTS " + departments));
    }
}

with the corresponding html page:

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
	<head>
		<title>SomePage</title>
	</head>
	<body>
		<span wicket:id="message">some page</span>
	</body>
</html>

To deploy the application to WebLogic, package the application as a war. Note that we do not need to package the jars as these are deployed separately as shared libraries. To deploy the application we create the following directory structure on the server where WebLogic runs:

wicketspringhibernate
	app
		wicket_spring_hibernate.war
	plan

When we deploy wicket_spring_hibernate.war, WebLogic will automatically create a deployment plan (Plan.xml) and a WEB-INF directory containing the weblogic.xml deployment override, in the plan directory. Open the weblogic.xml and add the following contents:

<weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.2/weblogic-web-app.xsd">
	<session-descriptor></session-descriptor>
	<jsp-descriptor></jsp-descriptor>
	<container-descriptor>
		<prefer-application-packages>
			<package-name>antlr.*</package-name>
		</prefer-application-packages>
	</container-descriptor>
	<context-root>/wsh</context-root>
	<library-ref>
		<library-name>hibernate</library-name>
		<specification-version>3.6</specification-version>
		<implementation-version>3.6.7</implementation-version>
		<exact-match>true</exact-match>
	</library-ref>
	<library-ref>
		<library-name>spring</library-name>
		<specification-version>3.0</specification-version>
		<implementation-version>3.0.6</implementation-version>
		<exact-match>true</exact-match>
	</library-ref>
	<library-ref>
		<library-name>wicket</library-name>
		<specification-version>1.5</specification-version>
		<implementation-version>1.5.1</implementation-version>
		<exact-match>true</exact-match>
	</library-ref>
</weblogic-web-app>

Here, we tell WebLogic to prefer the antlr package that is part of the application and tell WebLogic to merge the three deployed libraries with the application. Do not forget to update the deployment. The application can be tested by entering the following URL’s:

  • TestServlet – http://hostname:port/wsh/testservlet.
  • Wicket – http://hostname:port/wsh/somepage.

Sometimes it is necessary to obtain some run-time information from the WebLogic server, such as, the current sessions. In order to do this we can use JMX, for example,

package model.utils;

import javax.management.*;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.naming.Context;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;

public class JmxUtils {

    public static final String HOSTNAME = "localhost";
    public static final Integer PORT = 7001;
    public static final String USERNAME = "weblogic";
    public static final String PASSWORD = "magic11g";

    public static final String PROTOCOL = "t3";
    public static final String JNDI_ROOT = "/jndi/";

    public static final String MBEAN_SERVER = "weblogic.management.mbeanservers.domainruntime";
    public static final String SERVICE_NAME = "com.bea:Name=DomainRuntimeService,Type=weblogic.management.mbeanservers.domainruntime.DomainRuntimeServiceMBean";

    private JMXConnector connector;

    public JmxUtils() {
    }

    public RunTimeInfo getRunTimeInfomation() {
        return createRunTimeInfo();
    }

    private RunTimeInfo createRunTimeInfo() {
        RunTimeInfo runTimeInfo = null;

        try {
            MBeanServerConnection connection = getMBeanServerConnection();
            ObjectName service = new ObjectName(SERVICE_NAME);
            ObjectName[] serverRunTimes = (ObjectName[]) connection.getAttribute(service, "ServerRuntimes");

            runTimeInfo = new RunTimeInfo();
            runTimeInfo.setServerRunTimeInfos(new ArrayList<ServerRunTimeInfo>());

            for (int i = 0; i &lt; serverRunTimes.length; i++) {
                ServerRunTimeInfo serverRunTimeInfo = new ServerRunTimeInfo();
                serverRunTimeInfo.setServerName((String) connection.getAttribute(serverRunTimes[i], "Name"));
                serverRunTimeInfo.setServerVersion((String) connection.getAttribute(serverRunTimes[i], "WeblogicVersion"));
                serverRunTimeInfo.setServerState((String) connection.getAttribute(serverRunTimes[i], "State"));

                runTimeInfo.getServerRunTimeInfos().add(serverRunTimeInfo);
            }

            for (int i = 0; i &lt; serverRunTimes.length; i++) {
                ObjectName[] applicationRuntimes = (ObjectName[]) connection.getAttribute(serverRunTimes[i], "ApplicationRuntimes");
                runTimeInfo.setApplicationRunTimeInfos(new ArrayList<ApplicationRunTimeInfo>());

                for (int j = 0; j &lt; applicationRuntimes.length; j++) {
                    ApplicationRunTimeInfo applicationRunTimeInfo = new ApplicationRunTimeInfo();
                    applicationRunTimeInfo.setApplicationName((String) connection.getAttribute(applicationRuntimes[j], "Name"));

                    ObjectName[] componentRuntimes = (ObjectName[]) connection.getAttribute(applicationRuntimes[j], "ComponentRuntimes");

                    applicationRunTimeInfo.setComponentRunTimeInfos(new ArrayList<ComponentRunTimeInfo>());

                    for (int k = 0; k &lt; componentRuntimes.length; k++) {
                        if (connection.getAttribute(componentRuntimes[k], "Type").equals("WebAppComponentRuntime")) {
                            ComponentRunTimeInfo componentRunTimeInfo = new ComponentRunTimeInfo();
                            componentRunTimeInfo.setComponentName((String) connection.getAttribute(componentRuntimes[k], "Name"));
                            componentRunTimeInfo.setSessionsCurrent((Integer) connection.getAttribute(componentRuntimes[k], "OpenSessionsCurrentCount"));
                            componentRunTimeInfo.setSessionsHigh((Integer) connection.getAttribute(componentRuntimes[k], "OpenSessionsHighCount"));

                            applicationRunTimeInfo.getComponentRunTimeInfos().add(componentRunTimeInfo);
                        }
                    }
                    runTimeInfo.getApplicationRunTimeInfos().add(applicationRunTimeInfo);
                }
            }

            closeJmxConnector();
        } catch (MalformedObjectNameException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ReflectionException e) {
            e.printStackTrace();
        } catch (InstanceNotFoundException e) {
            e.printStackTrace();
        } catch (AttributeNotFoundException e) {
            e.printStackTrace();
        } catch (MBeanException e) {
            e.printStackTrace();
        }

        return runTimeInfo;
    }

    private MBeanServerConnection getMBeanServerConnection() throws IOException {
        return getJmxConnector().getMBeanServerConnection();
    }

    private JMXConnector getJmxConnector() throws IOException {
        JMXServiceURL serviceURL = new JMXServiceURL(PROTOCOL, HOSTNAME, PORT, JNDI_ROOT + MBEAN_SERVER);

        Hashtable hashtable = new Hashtable();
        hashtable.put(Context.SECURITY_PRINCIPAL, USERNAME);
        hashtable.put(Context.SECURITY_CREDENTIALS, PASSWORD);
        hashtable.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES, "weblogic.management.remote");

        connector = JMXConnectorFactory.connect(serviceURL, hashtable);
        return connector;
    }

    private void closeJmxConnector() throws IOException {
        connector.close();
    }
}

In the example above, we obtain server run-time information and application run-time information. If the application component is an instance of WebAppComponentRuntime we can access information, such as, the number of current sessions. More information regarding run-time MBeans can be found here. For example to obtain information about the ServerRuntimeMBean: open the tree Runtime MBeans, ServerRuntimeMBean and click Attributes to see the available attributes (such as Name, WeblogicVersion, State etcetera).

The following shows an example of the JMX output:

Server Name: AdminServer, Server Version: WebLogic Server 10.3.5.0 Fri Apr 1 20:20:06 PDT 2011 1398638 , Server State: RUNNING
Application Name: wicketspringhibernate
- Component Name: AdminServer_/wsh, Sessions Current: 1, Sessions High: 1
Application Name: bea_wls9_async_response
- Component Name: AdminServer_/_async, Sessions Current: 0, Sessions High: 0
Application Name: mejb
Application Name: consoleapp
- Component Name: AdminServer_/console, Sessions Current: 1, Sessions High: 2
- Component Name: AdminServer_/consolehelp, Sessions Current: 0, Sessions High: 0
Application Name: bea_wls_internal
- Component Name: AdminServer_/bea_wls_internal, Sessions Current: 0, Sessions High: 0
Application Name: ExampleDataSource

References

[1] Spring Framework Reference Documentation.
[2] Hibernate Reference Documentation.
[3] Apache Wicket.


Fun with Spring

In this post we are going to have a little fun with Spring. We show how dependency injection works, how to provide aspects to beans, see how to integrate Hibernate, how to obtain resources such as data sources, JMS connection factories and JMS queues from JNDI, how to create message-driven pojos, how to use commonj WorkManagers on which the thread model of WebLogic is based such that Spring does not spawn unmanaged threads, and if that was not enough see how to use Spring MVC. How good can it get, I love this stuff, hope you do too!

What is Spring?

Spring is a container/framework for dependence injection and aspect oriented programming (AOP), i.e.,

  • Dependency injection – objects get their dependencies in a passive manner, instead of creating objects by hand.
  • Aspect oriented – cohesive development by separating application logic from system services, such as transactions.
  • Container – contains and manages the lifecycle and configuration of the application objects.
  • Framework – configure and compose complex applications by using simple components.

Dependency injection

In a Spring-based application, the objects live in the Spring container. The container creates the objects, wires the objects, configures the objects and manages the objects lifecycle. Two Spring containers are available:

  • Bean factories (BeanFactory provide the basis for dependency injection.
  • Application contexts (ApplicationContext built upon bean factories by providing application services.

The following gives an example of how bean wiring (creating assocations between application components) works:

<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 id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mappingResources">
            <list>
                <value>model/entities/Department.hbm.xml</value>
                <value>model/entities/Employee.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.current_session_context_class">${hibernate.current_session_context_class}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
            </props>
        </property>
    </bean>
    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="jdbc/exampleDS"/>
        <property name="resourceRef" value="true"/>
    </bean>
</beans>

Note that in the example above properties are referenced by using ${hibernate.dialect}, in order for this to work we need to add the following bean:

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="locations">
		<list>
			<value>classpath:spring.properties</value>
		</list>
	</property>
</bean>

in which spring.properties is a custom file that is placed in the root of the classpath. This information is provided to Spring by using classpath:. Note that the properties file is nothing more than a basic key/value pair file, i.e.,

hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
hibernate.current_session_context_class=thread
hibernate.show_sql=false
hibernate.format_sql=false

As we are talking about properties. When configuring we sometimes run into the issue that we need to configure a bean that contains a java.util.Date. By default, we can configure bean properties by using basic Java objects, such as Strings. To be able to set properties of type java.util.Date as a String we have to configure the following:

<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
	<property name="customEditors">
		<map>
			<entry key="java.util.Date" value-ref="customDateEditor"/>
		</map>
	</property>
</bean>
<bean id="customDateEditor" class="org.springframework.beans.propertyeditors.CustomDateEditor">
	<constructor-arg ref="simpleDateFormat"/>
	<constructor-arg value="false"/>
</bean>
<bean id="simpleDateFormat" class="java.text.SimpleDateFormat">
	<constructor-arg value="dd-MM-yyyy"/>
</bean>

Spring now automatically converts a String to a Date object. Note that this is not handled by Spring itself but by a JavaBeans API feature. The interface PropertyEditor provides the possibility to map String values to other types. A handy implementation of the PropertyEditor interface is PropertyEditorSupport that contains two useful methods:

  • getAsText – gets the property value as a String.
  • setAsText(String value) – sets the property value by parsing a given String.

When we try to map a String value to another type, the setAsText method is called to execute the conversion. Spring provides a couple of editors which are based on PropertyEditorSupport, such as CustomDateEditor(DateFormat dateFormat, boolean allowEmpty). This class is used to convert a String to a Date and vice versa. The CustomEditorConfigurer is a so-called BeanFactoryPostProcessor which load editors in the BeanFactory by calling the registerCustomEditor method.

Aspect oriented programming

Systems typically consist of a number of components that are each responsible for a specific piece of functionality. These components usually use some kind of system service, such as transactions. System services are used by multiple components. Now we could duplicate code into each of the components that use system services or we could configure it and Spring handle it. Of course we are going for the latter option as we do not want our code to be obfuscated by code that is not part of the core functionality.

It may help to think of aspects as blankets that cover many components of an application. At its core, an application consists of modules that implement business functionality. With AOP, we can cover the core application with layers of functionality. These layers can be applied declarative throughout the application in a manner without the core application even knowing they exist. This is a powerful concept, as it keeps the transaction (and, for example, security) concerns from littering the application’s core business logic.

Aspects help to modularize cross-cutting concerns. In short, a cross-cutting concern can be described as any functionality that affects multiple points of an application. Security, for example, is a cross-cutting concern in that many methods in an application can have security rules applied to them. A common object-oriented technique for reusing common functionality is to apply inheritance or delegation. But inheritance can lead to a brittle object hierarchy if the same base class is used throughout an application, and delegation can be cumbersome because complicated calls to the delegate object may be required. Aspects offer an alternative to inheritance and delegation that can be cleaner in many circumstances. With AOP, we still define the common functionality in one place, but we can declarative define how and where this functionality is applied without having to modify the class to which we are applying the new feature. Cross-cutting concerns can now be modularized into special objects called aspects. This has two benefits:

  • First, the logic for each concern is now in one place, as opposed to being scattered all over the code base.
  • Second, our service modules are now cleaner since they only contain code for their primary concern (or core functionality) and secondary concerns have been moved to aspects.

Aspects are often described in terms of advice, pointcuts, and joinpoints. Aspects have a purpose – a job that they are meant to do. In AOP terms, the job of an aspect is called advice. Advice defines both the what and the when of an aspect. In addition to describing the job that an aspect will perform, advice addresses the question of when to perform the job. Should it be applied before a method is invoked? After the method is invoked? Both before and after method invocation? Or should it only be applied if a method throws an exception?

An application has opportunities for an advice to be applied. These opportunities are known as joinpoints. A joinpoint is a point in the execution of the application where an aspect can be plugged in. This point could be a method being called, an exception being thrown, or a field being modified. These are the points where the aspect’s code can be inserted into the normal flow of the application to add new behavior.

An aspect does not necessarily advise all joinpoints in an application. Pointcuts help narrow down the joinpoints advised by an aspect. If an advice defines the what and when of aspects then pointcuts define the where. A pointcut definition matches one or more joinpoints at which advice should be woven. Often we specify these pointcuts using explicit class and method names or through regular expressions that define matching class and method name patterns.

An aspect is the merger of advice and pointcuts. Taken together, advice and pointcuts define everything there is to know about an aspect – what it does and where and when it does it. Spring employs AOP to provide enterprise services such as declarative transactions. Transactions allow us to group several operations into a single unit of work that either fully happens or fully does not happen. When writing to a database, we must ensure that the integrity of the data is maintained by performing the updates within a transaction.

A transaction can be described by the acronym ACID. In short, ACID stands for:

  • Atomic – Transactions are made up of one or more activities bundled together as a single unit of work. Atomicity ensures that all the operations in the transaction happen or that none of them happen. If all the activities succeed, the transaction is a success. If any of the activities fail, the entire transaction fails and is rolled back.
  • Consistent – Once a transaction ends, the system is left in a state that is consistent with the business that it models. The data should not be corrupted with respect to reality.
  • Isolated – Transactions should allow multiple users to work with the same data, without each user’s work getting tangled up with the others. Therefore, transactions should be isolated from each other, preventing concurrent reads and writes to the same data from occurring. (Note that isolation typically involves locking rows and/or tables in a database.)
  • Durable – Once the transaction has completed, the results of the transaction should be made permanent so that they will survive any sort of system crash. This typically involves storing the results in a database or some other form of persistent storage.

Spring provides support for both programmatic and declarative transaction management support. While programmatic transaction management affords flexibility in precisely defining transaction boundaries in the code, declarative transactions help to decouple an operation from its transaction rules. Choosing between programmatic and declarative transaction management is largely a decision of fine-grained control versus convenience. Spring does not directly manage transactions. Instead, it comes with a selection of transaction managers that delegate responsibility for transaction management to a platform-specific transaction implementation provided by either JTA or the persistence mechanism. To use a transaction manager, we must declare it in the application context, for example,

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

Spring’s support for declarative transaction management is implemented through Spring’s AOP framework. A Spring transaction is sort of an aspect that ‘wraps’ a method with transactional boundaries. In Spring, declarative transactions are defined with transaction attributes. A transaction attribute is a description of how transaction policies should be applied to a method. To declare transactions we must set five parameters, which govern how transaction policies are administered:

  • Propagation behavior – Defines the boundaries of the transaction with respect to the client and to the method being called.
  • Isolation level – Defines how much a transaction may be impacted by the activities of other concurrent transactions. Realizing that perfect isolation can impact performance and because not all applications will require perfect isolation, sometimes it is desirable to be flexible with regard to transaction isolation.
  • Read-only – If a transaction performs only read operations against the underlying data store, the data store may be able to apply certain optimizations that take advantage of the read-only nature of the transaction. By declaring a transaction as read-only, we give the underlying data store the opportunity to apply those optimizations as it sees fit.
  • Transaction timeout – For an application to perform well, its transactions can not carry on for a long time. Suppose that the transaction becomes unexpectedly long-running. Because transactions may involve locks on the underlying data store, long-running transactions can tie up database resources unnecessarily. Instead of waiting it out, we can declare a transaction to automatically roll back after a certain number of seconds.
  • Rollback rules – A set of rules that define what exceptions prompt a rollback and which ones do not. By default, transactions are rolled back only on runtime exceptions and not on checked exceptions. However, we can declare that a transaction be rolled back on specific checked exceptions as well as runtime exceptions. Likewise, we can declare that a transaction not roll back on specified exceptions, even if those exceptions are runtime exceptions.

Declarative transaction management is accomplished by proxying classes with Spring’s TransactionProxyFactoryBean, for example,

<bean id="departmentDAOTarget" class="model.logic.DepartmentDAOBean">
	<property name="hibernateTemplate" ref="hibernateTemplate"/>
</bean>
<bean id="departmentDAO" parent="transactionTemplate">
	<property name="target" ref="departmentDAOTarget"/>
	<property name="proxyInterfaces" value="model.logic.DepartmentDAO"/>
</bean>
<bean id="transactionTemplate" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
	<property name="transactionManager" ref="transactionManager"/>
	<property name="transactionAttributes">
		<props>
			<prop key="add*">PROPAGATION_REQUIRED</prop>
			<prop key="remove*">PROPAGATION_REQUIRED</prop>
			<prop key="update*">PROPAGATION_REQUIRED</prop>
			<prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop>
		</props>
	</property>
</bean>

The second bean entry (transactionTemplate) is an abstract declaration which is used as a template. From this abstract declaration, we can make any number of beans transactional by using transactionTemplate as the parent declaration of the bean.

The DepartmentDAOBean has no idea that its methods are being called within the context of a transaction. If any object makes calls directly to the DepartmentDAOBean, those calls will not be transactional. Instead, collaborating objects should invoke methods on the proxy that is produced by TransactionProxyFactoryBean. The proxy will ensure that transactional rules are applied and then proxy the call to the real DepartmentDAOBean. Therefore, rather than inject the service directly into those objects that use it, we will inject the DepartmentDAOBean proxy into those objects. This means that the proxy produced by TransactionProxyFactoryBean must pretend to be a DepartmentDAOBean. That is the purpose of the proxyInterfaces property. Here we are telling TransactionProxyFactoryBean to produce a proxy that implements the DepartmentDAO interface. The transactionManager property supplies the appropriate transaction manager bean.

TransactionProxyFactoryBean will use the transaction manager to start, suspend, commit, and roll back transactions based on the transaction attributes defined in the transactionAttributes property of TransactionProxyFactoryBean. The transactionAttributes property declares which methods are to be run within a transaction and what the transaction attributes are to be. This property is given a props collection where the key of each prop is a method name pattern and the value defines the transaction attributes for the method(s) selected. The value of each prop given to the transactionAttributes property is a comma-separated value (Propagation Behavior, Isolation Level – Optional, Is the transaction read only? – Optional, Rollback Rules (-Exception, +Exception) – Optional). Note that a ‘-’ prefix forces a rollback while a ‘+’ prefix specifies commit (this allows commit on unchecked exceptions). In the case of the DepartmentDAOBean, we are declaring that all methods whose name starts with add should be run within a transaction. Methods starting with find support transactions (but do not necessarily require a transaction) and are read-only.

We can also accomplish this by using annotations, the only thing we need to add to the Spring application context is:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
	...
	<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
	<tx:annotation-driven/>
</beans>

Note that the transaction-manager attribute of tx:annotation-driven defaults to transactionManager and needs to be specified when an other name is used. The tx:annotation-driven configuration element tells Spring to examine the beans in the application context and to look for beans that are annotated with Transactional. For every bean that is Transactional, tx:annotation-driven will automatically advise it with transaction advice. The transaction attributes of the advice will be defined by parameters of the Transactional annotation. In our code we can use the following:

package model.logic;

import org.hibernate.criterion.DetachedCriteria;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public abstract class GenericHibernateSpringDAO<T, ID extends Serializable> implements GenericDAO<T, ID> {

    private Class<T> persistentClass;
    private HibernateTemplate hibernateTemplate;

    public GenericHibernateSpringDAO() {
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            setPersistentClass((Class<T>) parameterizedType.getActualTypeArguments()[0]);
        } else {
            System.out.println("Not an instance of parameterized type: " + type);
        }
    }

    public Class<T> getPersistentClass() {
        return persistentClass;
    }

    public void setPersistentClass(Class<T> persistentClass) {
        this.persistentClass = persistentClass;
    }

    public HibernateTemplate getHibernateTemplate() {
        return hibernateTemplate;
    }

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

    public T addEntity(T entity) {
        getHibernateTemplate().save(entity);
        return entity;
    }

    public void removeEntity(ID id) {
        getHibernateTemplate().delete(findEntity(id));
    }

    public void updateEntity(T entity) {
        getHibernateTemplate().update(entity);
    }

    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public T findEntity(ID id) {
        return (T) getHibernateTemplate().get(getPersistentClass(), id);
    }

    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public List<T> findEntities() {
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(getPersistentClass());
        return getHibernateTemplate().findByCriteria(detachedCriteria);
    }
}

Integrating Hibernate

Hibernate (an object/relational mapping framework) defines a technique to map an object oriented data model to a relational data model.

Even though there are many steps to the data access process, we are only actively involved in a couple of those steps. The carrier itself is responsible for driving the process. We are only involved when we need to be; the rest is just ‘taken care of’. This mirrors a powerful design pattern: the Template Method pattern. A template method defines the skeleton of a process. The process itself is fixed; it never changes. At certain points, however, the process delegates its work to a subclass to fill in some implementation-specific details. In software terms, a template method delegates the implementation-specific portions of the process to an interface. Different implementations of this interface define specific implementations of this portion of the process.

This is the same pattern that Spring applies to data access. No matter what technology we are using, certain data access steps are required. For example, we always need to obtain a connection to our data store and clean up resources when we are done. These are the fixed steps in a data access process. But each data access method we write is slightly different. We query for different objects and update the data in different ways. These are the variable steps in the data access process. Spring separates the fixed and variable parts of the data access process into two distinct classes, templates and callbacks:

  • Templates manage the fixed part of the process.
  • Callbacks handle the variable part, such as custom data access code.

Spring’s template classes handle the fixed parts of data access – controlling transactions, managing resources, and handling exceptions. Meanwhile, the specifics of data access as they pertain to the application – creating statements, binding parameters, and marshaling result sets – are handled in the callback implementation. In practice, this makes for an elegant framework because all we have to worry about is the data access logic. Spring comes with several templates to choose from, depending on the persistence platform choice. When using Hibernate then we can use HibernateTemplate as was done in the example above.

Applications that have a persistent state must in one way or another have interaction with the persistence provider, when a certain in-memory state must be persisted to the database (or vice versa). In the case of Hibernate this is the interface Session. Each Session is associated with a persistence context. A persistence context is some sort of cache that tracks object changes in a certain transaction. Note that Spring’s HibernateTemplate provides an abstract layer for the Session interface.

The complete Spring configuration looks as follows:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
    <bean id="departmentDAO" class="model.logic.DepartmentDAOBean">
        <property name="hibernateTemplate" ref="hibernateTemplate"/>
    </bean>
    <bean id="employeeDAO" class="model.logic.EmployeeDAOBean">
        <property name="hibernateTemplate" ref="hibernateTemplate"/>
    </bean>
    <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mappingResources">
            <list>
                <value>model/entities/Department.hbm.xml</value>
                <value>model/entities/Employee.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.current_session_context_class">${hibernate.current_session_context_class}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
            </props>
        </property>
    </bean>
    <bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
        <property name="driverType" value="${jdbc.driverClassName}"/>
        <property name="URL" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:spring.properties</value>
            </list>
        </property>
    </bean>
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    <tx:annotation-driven/>
</beans>

Obtaining beans

Now, that we have the configuration in place we need a way to obtain the configured beans. In Spring, objects are not responsible for finding or creating other objects that they need to do their job. Instead, they are given references to the objects that they collaborate with by the container. The act of creating these associations between application objects is the essence of dependency injection and is commonly referred to as wiring. Spring comes with several container implementations that can be categorized into two distinct types:

  • Bean factories provide basic dependency injection support. A bean factory is an implementation of the Factory design pattern, i.e., it is a class whose responsibility it is to create and dispense beans and is able to create associations between collaborating objects as they are instantiated. A bean factory also takes part in the lifecycle of a bean, such as making calls to initialization and destruction methods, if those methods are defined.
  • Application contexts provide application framework services, such as the ability to resolve textual messages from a properties file and the ability to publish application events to interested event listeners.

Before we can retrieve a bean from the application context, it needs to be created. This can be accomplished by using ClassPathXmlApplicationContext (Loads a context definition from an XML file located in the classpath, treating context definition files as classpath resources). Once we have an ApplicationContext instance we can use the getBean method to retrieve a bean, for example,

package model.utils;

import model.logic.DepartmentDAO;
import model.logic.EmployeeDAO;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Utilities {

    private static ApplicationContext context;

    private Utilities() {
    }

    static {
        context = new ClassPathXmlApplicationContext("spring-config.xml");
    }

    public static DepartmentDAO getDepartmentDAO() {
        return (DepartmentDAO) context.getBean("departmentDAO");
    }

    public static EmployeeDAO getEmployeeDAO() {
        return (EmployeeDAO) context.getBean("employeeDAO");
    }
}

A difference between an application context and a bean factory is how singleton beans are loaded. A bean factory lazily loads all beans, deferring bean creation until the getBean method is called. An application context is a bit smarter and preloads all singleton beans upon context start up. To take advantage of the opportunities offered by Spring to customize bean creation we have to understand the lifecycle:

  1. Instantiate – instantiate the bean.
  2. Populate properties – inject the bean’s properties.
  3. Set bean name – if the bean implements BeanNameAware, the bean’s ID is passed to setBeanName.
  4. Set bean factory – if the bean implements BeanFactoryAware, the bean factory is passed to setBeanFactory. If the bean implements ApplicationContextAware interface, the setApplicationContext method is called.
  5. Postprocess – if there are any BeanPostProcessors, Spring calls the postProcessBeforeInitialization method.
  6. Initialize beans – if the bean implements InitializingBean, the afterPropertiesSet method will be called. If the bean has an init-method declared, the specified method will be called.
  7. Postprocess – if there are any BeanPostProcessors, the postProcessAfterInitialization method will be called.
  8. At this point the bean is ready to be used by the application and will remain in the bean factory until it is no longer needed.
  9. Destroy bean – if the bean implements DisposableBean, the destroy method will be called. If the bean has a destroy-method declared, the specified method will be called.

By default, all Spring beans are singletons, i.e., when the container dispenses a bean it will always hand out the exact same instance of the bean. When declaring a bean in Spring, we have the option of declaring a scope for the bean. For example, to let Spring produce a new bean instance each time one is needed, we must declare the bean’s scope attribute to be prototype, for example

<bean id="cacheStore" class="com.tangosol.coherence.hibernate.HibernateCacheStore" scope="prototype">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

Spring offers a handful scoping options:

  • singleton – scopes the bean definition to a single instance per container (default).
  • prototype – allows a bean to be instantiated any number of times (once per use).
  • request – scopes a bean definition to an HTTP request. Only valid when used with a web capable Spring context (such as with Spring MVC).
  • session – scopes a bean definition to an HTTP session. Only valid when used with a web capable Spring context (such as with Spring MVC).
  • global-session – scopes a bean definition to a global HTTP session. Only valid when used in a portlet context.

Usually, the scope will be singleton, sometimes the prototype scope is useful, for example, when other programs need to manage the life cycle.

Obtain objects from JNDI

In distributed applications some components need to access resources, such as, database servers and messaging systems. Resources are typically identified by a unique name – a JNDI name and are in general configured on an application server. When we need objects that are not configured as beans in Spring but in JNDI we can use JndiObjectFactoryBean.

When the application is deployed on the server where the resources, such as data sources, are configured we can proceed as follows. To create a data source bean we add the following entry:

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
	<property name="jndiName" value="jdbc/exampleDS"/>
	<property name="resourceRef" value="true"/>
</bean>

In order for this work we need to add the following entry in the web.xml file

<resource-ref>
	<res-ref-name>jdbc/exampleDS</res-ref-name>
	<res-type>javax.sql.DataSource</res-type>
	<res-auth>Container</res-auth>
</resource-ref>

The resource-ref makes the resource known to the (Web) container. The container makes the resources available in the local java:comp/env/ environment.

To access resources remotely, we first have to define a JNDI template, for example,

<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
	<property name="environment">
		<props>
			<prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
			<prop key="java.naming.provider.url">t3://hostname:portnumber</prop>
		</props>
	</property>
</bean>

To create beans of remote resources, we can use the following

<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
	<property name="jndiTemplate" ref="jndiTemplate"/>
	<property name="jndiName" value="jms/ConnectionFactory"/>
</bean>
<bean id="destination" class="org.springframework.jndi.JndiObjectFactoryBean">
	<property name="jndiTemplate" ref="jndiTemplate"/>
	<property name="jndiName" value="jms/Queue"/>
</bean>

Now that we know how to retrieve resources, let us use this in an example that uses messaging.

Messaging

JMS can be divided into two functional areas, i.e., production and consumption of messages. The building blocks of a JMS application constist of:

  • Administrative objects (usually configured in an application server)
    • Connection factories – @Resource(name = "jms/ConnectionFactory", type = ConnectionFactory.class) ConnectionFactory connectionFactory;
    • Destinations (Queues or Topics) – @Resource(name = "jms/CompanyQueue", type = Queue.class) Queue destination;
  • Connections – Connection connection = connectionFactory.createConnection();
  • Sessions – Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
  • Message producers – MessageProducer messageProducer = session.createProducer(destination);
  • Message consumers – MessageConsumer messageConsumer = session.createConsumer(otherDestination);
  • Messages – ObjectMessage message = session.createObjectMessage(); message.setObject(person); messageProducer.send(message);

Just as that Spring offers templates for data access it also provides a JMSTemplate. The JMSTemplate can be used for message production and synchronous message consumption. For asynchronous consumption (such as message-driven beans), a message listener container can be used. To create a JMSTemplate we can use the following:

<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
	<property name="connectionFactory" ref="connectionFactory"/>
	<property name="defaultDestination" ref="destination"/>
</bean>

Code that uses a JMSTemplate only needs to implement a callback interface. For example, MessageCreator creates a message using a Session that is provided by the JMSTemplate:

package model.logic;

import model.entities.Department;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

import javax.jms.*;

public class JMSSender {

    private JmsTemplate jmsTemplate;

    public JmsTemplate getJmsTemplate() {
        return jmsTemplate;
    }

    public void setJmsTemplate(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    public void sendTextMessage() {
        getJmsTemplate().send(new MessageCreator(){
            public Message createMessage(Session session) throws JMSException {
                TextMessage message = session.createTextMessage();
                message.setText("Testing the JMS set-up one-two, one-two test");
                return message;
            }
        });
    }

    public void sendMessage(final Department department) {
        getJmsTemplate().send(new MessageCreator() {
            public Message createMessage(Session session) throws JMSException {
                ObjectMessage message = session.createObjectMessage();
                message.setObject(department);
                return message;
            }
        });
    }
}

To inject the JMSTemplate into the JMSSender we can use the following:

<bean id="sender" class="model.logic.JMSSender">
	<property name="jmsTemplate" ref="jmsTemplate"/>
</bean>

To receive messages asynchronously we can use message listener containers (Spring’s equivalent to message-driven beans). A message listener container is used to receive messages from a queue and drive the MessageListener that is injected into it. The listener container is responsible for all the threading of message consumption and dispatches to the listener for processing. Three message listeners are available:

The following shows an example message listener container configuration:

<bean class="org.springframework.jms.listener.SimpleMessageListenerContainer">
	<property name="connectionFactory" ref="connectionFactory"/>
	<property name="destination" ref="destination"/>
	<property name="messageListener" ref="receiver"/>
</bean>
<bean id="receiver" class="model.logic.JMSReceiver"/>

in which the JMSReceiver looks as follows:

package model.logic;

import model.entities.Department;
import javax.jms.*;

public class JMSReceiver implements MessageListener {

    public void onMessage(Message message) {
        if (message instanceof TextMessage) {
            TextMessage text = (TextMessage) message;
            try {
                message.acknowledge();
                System.out.println("received the following message: " + text.getText());
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }

        if (message instanceof ObjectMessage) {
            ObjectMessage objectMessage = (ObjectMessage) message;
            try {
                message.acknowledge();
                Department department = (Department) objectMessage.getObject();
                System.out.println("received the following message: " + department);
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }
}

When we choose the run Spring JMS on an application server, for example WebLogic, we run into the fact that the threads spawned by Spring are unmanaged. To make sure the thread are managed we can couple the message listener container to a work manager. First we add the following entry to the web.xml file

<resource-ref>
	<res-ref-name>default</res-ref-name>
	<res-type>commonj.work.WorkManager</res-type>
	<res-auth>Container</res-auth>
	<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

Now, we are able to create the following TaskExecutor:

<bean id="taskExecutor" class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">
	<property name="workManagerName" value="java:comp/env/default"/>
	<property name="resourceRef" value="true"/>
</bean>

To inject the TaskExecutor into the message listener container we can use:

<bean class="org.springframework.jms.listener.SimpleMessageListenerContainer">
	<property name="connectionFactory" ref="connectionFactory"/>
	<property name="destination" ref="destination"/>
	<property name="messageListener" ref="receiver"/>
	<property name="taskExecutor" ref="taskExecutor"/>
</bean>

Spring MVC

Spring MVC is designed around a DispatcherServlet that dispatches requests to handlers. The default handler is a Controller interface. In general, application controllers will subclass controllers such as AbstractController. Basically, the following classes will be involved in processing a request:

  • The DispatcherServlet reads the configuration file (<dispatcher-servlet-name>-servlet.xml and creates a respository with configuration objects.
  • The DispatcherServlet acts as a front controller and delegates requests to other components (Controllers).
  • Based on handler mappings it is determined which controller should process the request. The handler mapping uses the URL to choose the appropriate controller.
  • The Controller processes the request that results in information that should be returned to the requester:
    • The information is made available as a Model.
    • The information is handed to a View (for example, a JSP), such that the Model can be formatted as HTML.
  • The controller packages the Model data and the name of the View into a ModelAndView object and gives this to the DispatcherServlet.
  • The DispatherServlet uses a ViewResolver to determine the View.
  • The DispatherServlet passes the Model data to the View.

Let us just give an example of how to set this up. First, we have to configure the DispatcherServlet in the web.xml file, for example,

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">
    <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-config.xml</param-value>
   </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/spring/*</url-pattern>
    </servlet-mapping>
</web-app>

Note that based on the servlet-name a certain Spring configuration file is loaded. In this case the name of the configuration file must be spring-servlet.xml. By using the context parameter contextConfigLocation we can control which other configuration files must be loaded from the classpath.

To create a Controller, we subclass the AbstractController. In this case we need to override the handleRequestInternal method, for example,

package userinterface.controllers;

import model.entities.Department;
import model.logic.DepartmentDAO;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

public class DepartmentController extends AbstractController {

    private DepartmentDAO departmentDAO;

    public DepartmentController() {
    }

    public DepartmentDAO getDepartmentDAO() {
        return departmentDAO;
    }

    public void setDepartmentDAO(DepartmentDAO departmentDAO) {
        this.departmentDAO = departmentDAO;
    }

    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        List<Department> departments = getDepartmentDAO().findEntities();
        if (departments != null) {
            for (Department department: departments) {
                System.out.println(department);
            }
        }

        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("departments", departments);
        modelAndView.setViewName("departments");
        return modelAndView;
    }
}

To inject the DepartmentDAO instance into the Controller we add the following in the spring-servlet.xml file:

<bean name="departmentController" class="userinterface.controllers.DepartmentController">
	<property name="departmentDAO" ref="departmentDAO"/>
</bean>

Note that the departmentDAO bean is configured in the spring-config.xml file.

The HandlerMapping is set-up as follows. By using a handler mapping we map incoming requests to appropriate handlers. When the request comes in, the DispatcherServlet will hand it over to the handler mapping to let it inspect the request and come up with the appropriate HandlerExecutionChain. Then the DispatcherServlet will execute the handler. A very handy handler mapping is the SimpleUrlHandlerMapping, for example,

<bean id="simpleUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	<property name="mappings">
		<props>
			<prop key="/departments.html">departmentController</prop>
		</props>
	</property>
</bean>

This handler mapping routes requests for departments.html to the departmentController.

Next, we need to resolve the view. To this end, Spring provides view resolvers, which enable us to render models in a browser without tying them to a specific view technology. The ViewResolver interface provides a mapping between view names and actual views. When using JSP as the view technology we can use the InternalResourceViewResolver, for example,

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/"/>
	<property name="suffix" value=".jsp"/>
</bean>

The following shows an example of a view in this case a JSP page (departments.jsp):

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
	<head><title>Departments</title></head>
	<body>
		<h1>Hello</h1>
		<table>
			<c:forEach items="${departments}" var="department">
				<tr>
					<td><c:out value="${department.departmentName}"/></td>
				</tr>
			</c:forEach>
		</table>
	</body>
</html>

Note that the departments variable is set by the departmentController through the returned ModelAndView instance. When we put a request in the form of http://hostname:port/<context-root>/spring/departments.html the following happens:

  • As we configured an url-mapping in the web.xml file, the /spring/* part of the URL makes sure that the DispatcherServlet handles the request.
  • The DispatcherServlet receives a request with the following URL /departments.html.
  • By using the SimpleUrlHandlerMapping the DispatcherServlet determines which controller to use. In this case it finds a mapping to the DepartmentController.
  • The DispatcherServlet passes the request to the DepartmentController.
  • The DepartmentController creates a ModelAndView object, in which
    • The Model contains a List with all the Department objects and maps this to a property named departments.
    • The View contains a logical name, in this case departments.
  • The DispatcherServlet uses the InternalResourceViewResolver to determine which JSP the Model has to render.
  • The DispatcherServlet passes the request to the departments.jsp page.

References

[1] Walls, “Spring in Action”, Manning, 2008. All you ever wanted to know about Spring (also a good reference when you are going for your Spring certification).
[2] The Spring Framework – Reference Documentation.


Implementing Coherence Cache Stores

In this post we look at how to create cache stores that need to ‘communicate’ with a database and JMS. Spring will be used to configure the necessary resources which will be injected into a Hibernate template and a JMS template that will be used by the cache store. We start with a basic set-up. Subsequently, we will discuss how to integrate Spring with Coherence and show an example which uses the HibernateCacheStore that ships with Coherence. After which we show how to use Spring’s HibernateTemplate to create a custom cache store. Finally, we present an example that integrates JMS as well by using Spring’s JMSTemplate.

Basic set-up

We have one entity

package model.entities;

import com.tangosol.io.ExternalizableLite;
import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PofWriter;
import com.tangosol.io.pof.PortableObject;
import com.tangosol.util.ExternalizableHelper;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.Serializable;

public class Klant implements PortableObject {

    private Integer klantnummer;
    private String naam;
    private String adres;
    private String stad;
    private String provincie;
    private String postcode;
    private Integer gebied;
    private String telefoonnummer;
    private Integer reputatieNummer;
    private Double kredietlimiet;
    private String commentaar;

    public Klant() {
    }

    public Integer getKlantnummer() {
        return klantnummer;
    }

    public void setKlantnummer(Integer klantnummer) {
        this.klantnummer = klantnummer;
    }

    public String getNaam() {
        return naam;
    }

    public void setNaam(String naam) {
        this.naam = naam;
    }

    public String getAdres() {
        return adres;
    }

    public void setAdres(String adres) {
        this.adres = adres;
    }

    public String getStad() {
        return stad;
    }

    public void setStad(String stad) {
        this.stad = stad;
    }

    public String getProvincie() {
        return provincie;
    }

    public void setProvincie(String provincie) {
        this.provincie = provincie;
    }

    public String getPostcode() {
        return postcode;
    }

    public void setPostcode(String postcode) {
        this.postcode = postcode;
    }

    public Integer getGebied() {
        return gebied;
    }

    public void setGebied(Integer gebied) {
        this.gebied = gebied;
    }

    public String getTelefoonnummer() {
        return telefoonnummer;
    }

    public void setTelefoonnummer(String telefoonnummer) {
        this.telefoonnummer = telefoonnummer;
    }

    public Integer getReputatieNummer() {
        return reputatieNummer;
    }

    public void setReputatieNummer(Integer reputatieNummer) {
        this.reputatieNummer = reputatieNummer;
    }

    public Double getKredietlimiet() {
        return kredietlimiet;
    }

    public void setKredietlimiet(Double kredietlimiet) {
        this.kredietlimiet = kredietlimiet;
    }

    public String getCommentaar() {
        return commentaar;
    }

    public void setCommentaar(String commentaar) {
        this.commentaar = commentaar;
    }

    @Override
    public boolean equals(Object object) {
        if (this == object) {
            return true;
        }

        if (object == null) {
            return false;
        }

        if (!(object instanceof Klant)) {
            return false;
        }

        Klant klant = (Klant) object;
        return klantnummer.equals(klant.getKlantnummer());
    }

    @Override
    public int hashCode() {
        if (klantnummer != null) {
            return 37 * klantnummer.hashCode();
        } else {
            return System.identityHashCode(this);
        }
    }

    @Override
    public String toString() {
        return naam + ", " + adres;
    }

    public void readExternal(PofReader reader) throws IOException {
        setKlantnummer(reader.readInt(0));
        setNaam(reader.readString(1));
        setAdres(reader.readString(2));
        setStad(reader.readString(3));
        setProvincie(reader.readString(4));
        setPostcode(reader.readString(5));
        setGebied(reader.readInt(6));
        setTelefoonnummer(reader.readString(7));
        setReputatieNummer(reader.readInt(8));
        setKredietlimiet(reader.readDouble(9));
        setCommentaar(reader.readString(10));
    }

    public void writeExternal(PofWriter writer) throws IOException {
        if (getKlantnummer() != null) {
            writer.writeInt(0, getKlantnummer());
        }
        if (getNaam() != null) {
            writer.writeString(1, getNaam());
        }
        if (getAdres() != null) {
            writer.writeString(2, getAdres());
        }
        if (getStad() != null) {
            writer.writeString(3, getStad());
        }
        if (getProvincie() != null) {
            writer.writeString(4, getProvincie());
        }
        if (getPostcode() != null) {
            writer.writeString(5, getPostcode());
        }
        if (getGebied() != null) {
            writer.writeInt(6, getGebied());
        }
        if (getTelefoonnummer() != null) {
            writer.writeString(7, getTelefoonnummer());
        }
        if (getReputatieNummer() != null) {
            writer.writeInt(8, getReputatieNummer());
        }
        if (getKredietlimiet() != null) {
            writer.writeDouble(9, getKredietlimiet());
        }
        if (getCommentaar() != null) {
            writer.writeString(10, getCommentaar());
        }
    }

    public void readExternal(DataInput dataInput) throws IOException {
        setKlantnummer(dataInput.readInt());
        setNaam(ExternalizableHelper.readSafeUTF(dataInput));
        setAdres(ExternalizableHelper.readSafeUTF(dataInput));
        setStad(ExternalizableHelper.readSafeUTF(dataInput));
        setProvincie(ExternalizableHelper.readSafeUTF(dataInput));
        setPostcode(ExternalizableHelper.readSafeUTF(dataInput));
        setGebied(dataInput.readInt());
        setTelefoonnummer(ExternalizableHelper.readSafeUTF(dataInput));
        setReputatieNummer(dataInput.readInt());
        setKredietlimiet(dataInput.readDouble());
        setCommentaar(ExternalizableHelper.readSafeUTF(dataInput));
    }

    public void writeExternal(DataOutput dataOutput) throws IOException {
        if (getKlantnummer() != null) {
            dataOutput.writeInt(getKlantnummer());
        }
        if (getNaam() != null) {
            ExternalizableHelper.writeSafeUTF(dataOutput, getNaam());
        }
        if (getAdres() != null) {
            ExternalizableHelper.writeSafeUTF(dataOutput, getAdres());
        }
        if (getStad() != null) {
            ExternalizableHelper.writeSafeUTF(dataOutput, getStad());
        }
        if (getProvincie() != null) {
            ExternalizableHelper.writeSafeUTF(dataOutput, getProvincie());
        }
        if (getPostcode() != null) {
            ExternalizableHelper.writeSafeUTF(dataOutput, getPostcode());
        }
        if (getGebied() != null) {
            dataOutput.writeInt(getGebied());
        }
        if (getTelefoonnummer() != null) {
            ExternalizableHelper.writeSafeUTF(dataOutput, getTelefoonnummer());
        }
        if (getReputatieNummer() != null) {
            dataOutput.writeInt(getReputatieNummer());
        }
        if (getKredietlimiet() != null) {
            dataOutput.writeDouble(getKredietlimiet());
        }
        if (getCommentaar() != null) {
            ExternalizableHelper.writeSafeUTF(dataOutput, getCommentaar());
        }
    }
}

Here, we have implemented PortableObject and ExternalizableLite. We use Hibernate as the persistence framework and have to following mapping for the entity

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="model.entities">
    <class name="Klant" table="CUSTOMER">
        <id name="klantnummer" type="integer" column="CUSTID">
            <generator class="assigned"/>
        </id>
        <property name="naam" type="string" column="NAME"/>
        <property name="adres" type="string" column="ADDRESS"/>
        <property name="stad" type="string" column="CITY"/>
        <property name="provincie" type="string" column="STATE"/>
        <property name="postcode" type="string" column="ZIP"/>
        <property name="gebied" type="integer" column="AREA"/>
        <property name="telefoonnummer" type="string" column="PHONE"/>
        <property name="reputatieNummer" type="integer" column="REPID"/>
        <property name="kredietlimiet" type="double" column="CREDITLIMIT"/>
        <property name="commentaar" type="string" column="COMMENTS"/>
    </class>
</hibernate-mapping>

We perform the basic persistence operations (insert, update, delete and select) for which we define the following interface

package model.logic;

import java.io.Serializable;
import java.util.List;

public interface GenericDAO<T, ID extends Serializable> {
    public void addEntity(ID id, T entity);

    public void removeEntity(ID id);

    public void updateEntity(ID id, T entity);

    public T findEntity(ID id);

    public List<T> findEntities();
}

We will use Coherence with the write-behind pattern for updating data through the cache. Thus the client only communicates with Coherence and we can implement the interface as follows:

package model.logic;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.util.MapTriggerListener;
import com.tangosol.util.ValueExtractor;
import com.tangosol.util.extractor.ChainedExtractor;
import com.tangosol.util.filter.EqualsFilter;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public abstract class GenericCoherenceDAO<T, ID extends Serializable> implements GenericDAO<T, ID> {

    private Class<T> persistentClass;
    private NamedCache namedCache;

    public GenericCoherenceDAO() {
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            setPersistentClass((Class<T>) parameterizedType.getActualTypeArguments()[0]);
        } else {
            System.out.println("Not an instance of parameterized type: " + type);
        }

        setNamedCache(CacheFactory.getCache(getPersistentClass().getName()));
    }

    public Class<T> getPersistentClass() {
        return persistentClass;
    }

    public void setPersistentClass(Class<T> persistentClass) {
        this.persistentClass = persistentClass;
    }

    public NamedCache getNamedCache() {
        return namedCache;
    }

    public void setNamedCache(NamedCache namedCache) {
        this.namedCache = namedCache;
    }

    public void addEntity(ID id, T entity) {
        getNamedCache().put(id, entity);
    }

    public void removeEntity(ID id) {
        getNamedCache().remove(id);
    }

    public void updateEntity(ID id, T entity) {
        getNamedCache().put(id, entity);
    }

    public T findEntity(ID id) {
        return (T) getNamedCache().get(id);
    }

    public List<T> findEntities() {
        ValueExtractor extractor = new ChainedExtractor("getClass.getName");
        Set keys = getNamedCache().keySet(new EqualsFilter(extractor, getPersistentClass().getName()));
        return new ArrayList<T>(getNamedCache().getAll(keys).values());
    }
}

By using a CacheStore we will tell Coherence how to communicate with certain resources, such as a database and JMS.

Specific entity functionality is implemented in entity specific DAOs, for example,

package model.logic;

import model.entities.Klant;

import java.util.Iterator;
import java.util.Map;

public interface KlantDAO extends GenericDAO<Klant, Integer> {
    public void preload();

    public Iterator<Map.Entry<Integer, Klant>> getKlantData();
}

Which is implemented as follows

package model.logic;

import com.tangosol.net.cache.ContinuousQueryCache;
import com.tangosol.util.Filter;
import com.tangosol.util.QueryHelper;
import model.entities.Klant;
import model.util.events.ContinuousCacheListener;
import model.util.loader.*;

import java.util.Iterator;
import java.util.Map;

public class KlantDAOBean extends GenericCoherenceDAO<Klant, Integer> implements KlantDAO {

    private ContinuousQueryCache continuousQueryCache;

    public KlantDAOBean() {
        Filter filter = QueryHelper.createFilter("kredietlimiet between 4000.0 and 12000.0");
        continuousQueryCache = new ContinuousQueryCache(getNamedCache(), filter, new ContinuousCacheListener());
    }

    public void preload() {
        Source source = new HibernateSource(super.getNamedCache(), super.getPersistentClass());
        Target target = new CoherenceTarget(super.getNamedCache(), super.getPersistentClass(), "klantnummer");
        Loader loader = new Loader(source, target);
        loader.load();
    }

    public Iterator<Map.Entry<Integer, Klant>> getKlantData() {
        return continuousQueryCache.entrySet().iterator();
    }
}

This provides preloading and continuous query functionality for the Klant entity. To test the environment will use the following

package model.test;

import model.entities.Klant;
import model.logic.KlantDAO;
import model.logic.KlantDAOBean;

import java.util.Random;

public class Test {

    private Random generator = new Random();

    public static void main(String[] args) {
        Test test = new Test();

        KlantDAO klantDAO = new KlantDAOBean();

        test.doRandomReadWriteTest(klantDAO);
    }

    private void doRandomReadWriteTest(KlantDAO klantDAO) {
        klantDAO.preload();

        while (true) {
            // generate a random client
            Klant klant = createKlant();
            // insert or update a client - an update is issued when the client already exists
            klantDAO.addEntity(klant.getKlantnummer(), klant);
            if (generator.nextDouble() &lt; 0.001) {
                System.out.println("JACKPOT");
                // remove a client
                klantDAO.removeEntity(generateKlantNummer());
                // get all client data
                klantDAO.findEntities();
                // get data from the continuous query cache
                klantDAO.getKlantData();
            } else {
                // find a client by ID
                klantDAO.findEntity(generateKlantNummer());
            }
        }
    }

    private Klant createKlant() {
        int klantnummer = generateKlantNummer();

        Klant klant = new Klant();
        klant.setKlantnummer(klantnummer);
        klant.setNaam("Person" + klantnummer);
        klant.setAdres("Someware");
        klant.setStad("Else");
        klant.setProvincie("NL");
        klant.setPostcode("1234AB");
        klant.setGebied(1);
        klant.setTelefoonnummer("123-4567");
        klant.setReputatieNummer(1);
        klant.setKredietlimiet(Math.rint(generator.nextDouble() * 5000.0));
        klant.setCommentaar(Long.toString(Math.abs(generator.nextLong()), 36));

        return klant;
    }

    private Integer generateKlantNummer() {
        int klantnummer = generator.nextInt(10000);
        if (klantnummer == 0 || (klantnummer &gt;= 100 && klantnummer &lt;= 109)) {
            return 42;
        } else {
            return klantnummer;
        }
    }
}

Coherence and Spring

Access to Coherence caches and services are through the static factory methods provided by the CacheFactory class. These methods delegate to the ConfigurableCacheFactory interface. An implemention of this interface can be plugged-in by using the tangosol-coherence-override.xml file.

When configuring Coherence, we can provide our own CacheStore implementations. CacheStore implementations usually use some sort of resource, such as a data source. Spring provides the perfect way to configure all kinds of resources and manage the lifecycle of these resources. Thus it would be handy to use Spring constructs, such as transaction managers, data sources, etcetera. The SpringAwareCacheFactory provides, next to the facility to access caches in a Coherence configuration file, the ability to reference beans configured using Spring. The SpringAwareCacheFactory can be obtained here:

package com.tangosol.coherence.spring;

import com.tangosol.net.BackingMapManagerContext;
import com.tangosol.net.DefaultConfigurableCacheFactory;

import com.tangosol.run.xml.SimpleElement;
import com.tangosol.run.xml.XmlElement;
import com.tangosol.run.xml.XmlHelper;

import com.tangosol.util.ClassHelper;

import java.util.Iterator;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

/**
 * SpringAwareCacheFactory provides a facility to access caches declared in a "cache-config.dtd" compliant
 * configuration file, similar to its super class {@link DefaultConfigurableCacheFactory}.  In addition,
 * this factory provides the ability to reference beans in a Spring application context through the use
 * of a class-scheme element.
 * <p/>
 * This factory can be configured to start its own Spring application context from which to retrieve these
 * beans.  This can be useful for standalone JVMs such as cache servers.  It can also be configured at run
 * time with a preconfigured Spring bean factory.  This can be useful for Coherence applications running
 * in an environment that is itself responsible for starting the Spring bean factory, such as a web container.
 *
 * @see #instantiateAny(CacheInfo, XmlElement, BackingMapManagerContext, ClassLoader)
 */
public class SpringAwareCacheFactory extends DefaultConfigurableCacheFactory implements BeanFactoryAware {

    /**
     * Spring BeanFactory used by this CacheFactory
     */
    private BeanFactory m_beanFactory;

    /**
     * Prefix used in cache configuration "class-name" element to indicate this bean is in Spring.
     */
    private static final String SPRING_BEAN_PREFIX = "spring-bean:";

    /**
     * Construct a default DefaultConfigurableCacheFactory using the default configuration file name.
     */
    public SpringAwareCacheFactory() {
        super();
    }

    /**
     * Construct a SpringAwareCacheFactory using the specified path to a "cache-config.dtd" compliant configuration
     * file or resource.  This will also create a Spring ApplicationContext based on the supplied path to a Spring
     * compliant configuration file or resource.
     *
     * @param sCacheConfig location of a cache configuration
     * @param sAppContext  location of a Spring application context
     */
    public SpringAwareCacheFactory(String sCacheConfig, String sAppContext) {
        super(sCacheConfig);

        azzert(sAppContext != null && sAppContext.length() > 0, "Application context location required");

        m_beanFactory = sCacheConfig.startsWith("file:") ? (BeanFactory) new FileSystemXmlApplicationContext(sAppContext)
                : new ClassPathXmlApplicationContext(sAppContext);

        // register a shutdown hook so the bean factory cleans up upon JVM exit
        ((AbstractApplicationContext) m_beanFactory).registerShutdownHook();
    }

    /**
     * Construct a SpringAwareCacheFactory using the specified path to a "cache-config.dtd" compliant configuration
     * file or resource and the supplied Spring BeanFactory.
     *
     * @param sPath       the configuration resource name or file path
     * @param beanFactory Spring BeanFactory used to load Spring beans
     */
    public SpringAwareCacheFactory(String sPath, BeanFactory beanFactory) {
        super(sPath);

        m_beanFactory = beanFactory;
    }

    /**
     * Create an Object using the "class-scheme" element.
     * <p/>
     * In addition to the functionality provided by the super class, this will retreive an object from the
     * configured Spring BeanFactory for class names that use the following format:
     * <p/>
     * &lt;class-name&gt;spring-bean:sampleCacheStore&lt;/class-name&gt;
     * <p/>
     * Parameters may be passed to these beans through setter injection as well:
     * <p/>
     * &lt;init-params&gt;
     * &lt;init-param&gt;
     * &lt;param-name&gt;setEntityName&lt;/param-name&gt;
     * &lt;param-value&gt;{cache-name}&lt;/param-value&gt;
     * &lt;/init-param&gt;
     * &lt;/init-params&gt;
     * <p/>
     * Note that Coherence will manage the lifecycle of the instantiated Spring bean, therefore any beans that
     * are retrieved using this method should be scoped as a prototype in the Spring configuration file, for example:
     * <p/>
     * &lt;bean id="sampleCacheStore" class="com.company.SampleCacheStore" scope="prototype"/&gt;
     *
     * @param info     the cache info
     * @param xmlClass "class-scheme" element.
     * @param context  BackingMapManagerContext to be used
     * @param loader   the ClassLoader to instantiate necessary classes
     * @return a newly instantiated Object
     * @see DefaultConfigurableCacheFactory#instantiateAny(CacheInfo, XmlElement, BackingMapManagerContext, ClassLoader)
     */
    @Override
    public Object instantiateAny(CacheInfo info, XmlElement xmlClass, BackingMapManagerContext context, ClassLoader loader) {
        if (translateSchemeType(xmlClass.getName()) != SCHEME_CLASS) {
            throw new IllegalArgumentException("Invalid class definition: " + xmlClass);
        }

        String sClass = xmlClass.getSafeElement("class-name").getString();

        if (sClass.startsWith(SPRING_BEAN_PREFIX)) {
            String sBeanName = sClass.substring(SPRING_BEAN_PREFIX.length());

            azzert(sBeanName != null && sBeanName.length() > 0, "Bean name required");

            XmlElement xmlParams = xmlClass.getElement("init-params");
            XmlElement xmlConfig = null;
            if (xmlParams != null) {
                xmlConfig = new SimpleElement("config");
                XmlHelper.transformInitParams(xmlConfig, xmlParams);
            }

            Object oBean = getBeanFactory().getBean(sBeanName);

            if (xmlConfig != null) {
                for (Iterator iter = xmlConfig.getElementList().iterator(); iter.hasNext();) {
                    XmlElement xmlElement = (XmlElement) iter.next();

                    String sMethod = xmlElement.getName();
                    String sParam = xmlElement.getString();
                    try {
                        ClassHelper.invoke(oBean, sMethod, new Object[]{sParam});
                    } catch (Exception e) {
                        ensureRuntimeException(e, "Could not invoke " + sMethod + "(" + sParam + ") on bean " + oBean);
                    }
                }
            }
            return oBean;
        } else {
            return super.instantiateAny(info, xmlClass, context, loader);
        }
    }

    /**
     * Get the Spring BeanFactory used by this CacheFactory.
     *
     * @return the Spring {@link BeanFactory} used by this CacheFactory
     */
    public BeanFactory getBeanFactory() {
        azzert(m_beanFactory != null, "Spring BeanFactory == null");
        return m_beanFactory;
    }

    /**
     * Set the Spring BeanFactory used by this CacheFactory.
     *
     * @param beanFactory the Spring {@link BeanFactory} used by this CacheFactory
     */
    public void setBeanFactory(BeanFactory beanFactory) {
        m_beanFactory = beanFactory;
    }
}

HibernateCacheStore

To set-up the HibernateCacheStore, which ships with the Coherence distribution we proceed as follows. We start with configuring Spring

<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 id="cacheStore" class="com.tangosol.coherence.hibernate.HibernateCacheStore" scope="prototype">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mappingResources">
            <list>
                <value>model/entities/Klant.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.c3p0.min_size">${connectionpool.minimum.size}</prop>
                <prop key="hibernate.c3p0.max_size">${connectionpool.maximum.size}</prop>
                <prop key="hibernate.c3p0.timeout">${connectionpool.timeout}</prop>
                <prop key="hibernate.c3p0.max_statements">${connectionpool.maximum.statements}</prop>
                <prop key="hibernate.c3p0.idle_test_period">${connectionpool.idle.period}</prop>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.current_session_context_class">${hibernate.current_session_context_class}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
            </props>
        </property>
    </bean>
    <bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
        <property name="driverType" value="${jdbc.driverClassName}"/>
        <property name="URL" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:spring-config.properties</value>
            </list>
        </property>
    </bean>
</beans>

Here we have configured a dataSource that is injected into a Hibernate sessionFactory, which is used by the cacheStore. Note that the cacheStore bean has protoType as its scope. This forces Spring to produce a new bean instance each time one is needed and lets Coherence manage its life cycle when we refer to it in the Coherence configuration, for example,

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
              xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
    <defaults>
        <serializer>
            <instance>
                <class-name>com.tangosol.io.pof.ConfigurablePofContext</class-name>
                <init-params>
                    <init-param>
                        <param-type>String</param-type>
                        <param-value>pof-config.xml</param-value>
                    </init-param>
                </init-params>
            </instance>
        </serializer>
    </defaults>
    <caching-scheme-mapping>
        <cache-mapping>
            <cache-name>*</cache-name>
            <scheme-name>read-write-distributed</scheme-name>
            <init-params>
                <init-param>
                    <param-name>back-size-limit</param-name>
                    <param-value>250M</param-value>
                </init-param>
            </init-params>
        </cache-mapping>
    </caching-scheme-mapping>
    <caching-schemes>
        <distributed-scheme>
            <scheme-name>read-write-distributed</scheme-name>
            <service-name>ReadWriteDistributedCache</service-name>
            <thread-count>5</thread-count>
            <backup-count>1</backup-count>
            <backup-count-after-writebehind>0</backup-count-after-writebehind>
            <backing-map-scheme>
                <read-write-backing-map-scheme>
                    <scheme-ref>read-write-backing-map</scheme-ref>
                </read-write-backing-map-scheme>
            </backing-map-scheme>
            <autostart>true</autostart>
        </distributed-scheme>
        <read-write-backing-map-scheme>
            <scheme-name>read-write-backing-map</scheme-name>
            <internal-cache-scheme>
                <local-scheme>
                    <scheme-ref>backing-map</scheme-ref>
                </local-scheme>
            </internal-cache-scheme>
			<write-max-batch-size>512</write-max-batch-size>
            <cachestore-scheme>
                <class-scheme>
                    <class-name>spring-bean:cacheStore</class-name>
                    <init-params>
                        <init-param>
                            <param-name>setEntityName</param-name>
                            <param-value>{cache-name}</param-value>
                        </init-param>
                    </init-params>
                </class-scheme>
            </cachestore-scheme>
            <write-delay>{write-delay 10s}</write-delay>
            <write-batch-factor>{write-batch-factor 0.75}</write-batch-factor>
            <write-requeue-threshold>{write-requeue-threshold 512}</write-requeue-threshold>
            <refresh-ahead-factor>{refresh-ahead-factor 0.1}</refresh-ahead-factor>
        </read-write-backing-map-scheme>
        <local-scheme>
            <scheme-name>backing-map</scheme-name>
            <eviction-policy>hybrid</eviction-policy>
            <high-units>{back-size-limit 0}</high-units>
            <unit-calculator>binary</unit-calculator>
            <expiry-delay>{back-expiry-delay 1h}</expiry-delay>
        </local-scheme>
    </caching-schemes>
</cache-config>

Configured Spring beans can be referenced in the Coherence cache configuration by using spring-bean:<bean-id>. In our case this will be spring-bean:cacheStore. By specifying init-param elements, we can specify setters that will be injected into the bean with appropriate values. In this case, we inject the entityName attribute of the HibernateCacheStore with the name of the cache, which will be model.entities.Klant when we use KlantDAO klantDAO = new KlantDAOBean().

Now that we have the Spring and Coherence configuration in place, we need to tell Coherence about them. This can be accomplished by using the tangosol-coherence-override.xml operational override file, i.e.,

<coherence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config"
           xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-operational-config coherence-operational-config.xsd">
    <configurable-cache-factory-config>
        <class-name system-property="tangosol.coherence.cachefactory">com.tangosol.coherence.spring.SpringAwareCacheFactory</class-name>
        <init-params>
            <init-param>
                <param-type>java.lang.String</param-type>
                <param-value system-property="tangosol.coherence.cacheconfig">cache-config.xml</param-value>
            </init-param>
            <init-param id="1">
                <param-type>java.lang.String</param-type>
                <param-value system-property="tangosol.coherence.springconfig">spring-config.xml</param-value>
            </init-param>
        </init-params>
    </configurable-cache-factory-config>
</coherence>

This tells Coherence to use com.tangosol.coherence.spring.SpringAwareCacheFactory as the CacheFactory implementation, which is invoked by using the
SpringAwareCacheFactory(String sCacheConfig, String sAppContext)
constructor.

CustomCacheStore

Before we implement our own cache store implementation, we will discuss some of the cache configurations we have made in the set-up described above. To make sure that entries are requeued upon a store operation failure, we have to set the write-requeue-threshold to the maximum number of entries that can exist in the queue. The number of entries sent to the storeAll implementation is controlled by the write-max-batch-size setting which defaults to 128. If storeAll throws an exception, the read-write backing map requeues all entries still present in mapEntries.

The write-batch-factor is used to calculate the soft-ripe time for the entries in the queue. An entry in the queue is considered ripe when it has been in the queue for at least the time configured by the write-behind element. Conceptually, the write-behind thread uses the following logic:

  • The thread waits for a queued entry to become ripe.
  • The thread dequeues all ripe and soft-ripe entries in the queue.
  • The thread writes the entries by using store, if there is one entry, or storeAll, if there are multiple entries.

The store and storeAll implementations must be idempotent, which means that the operation can be invoked again without any side effects. Another thing is that there is no ordering guarantee, thus it is not advised to have store and storeAll implementations that have dependencies, such as referential integrity and validation on the database that is not performed in the application.

When using Spring and Hibernate, we can use the HibernateTemplate, to implement our cache store implementation, for example,

package model.util.readwrite;

import com.tangosol.net.cache.AbstractCacheStore;
import org.springframework.orm.hibernate3.HibernateTemplate;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class CustomCacheStore extends AbstractCacheStore {

    private Integer batchSize = 128;
    private HibernateTemplate hibernateTemplate;
    private String entityName;

    public Integer getBatchSize() {
        return batchSize;
    }

    public void setBatchSize(Integer batchSize) {
        this.batchSize = batchSize;
    }

    public HibernateTemplate getHibernateTemplate() {
        return hibernateTemplate;
    }

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

    public String getEntityName() {
        return entityName;
    }

    public void setEntityName(String entityName) {
        this.entityName = entityName;
    }

    @Override
    public Object load(Object key) {
        return findEntity(key);
    }

    @Override
    public void store(Object key, Object value) {
        getHibernateTemplate().saveOrUpdate(value);
    }

    @Override
    public void storeAll(Map mapEntries) {
        if (getBatchSize() == 0 || mapEntries.size() &lt; getBatchSize()) {
            storeBatch(mapEntries);
        } else {
            Map batch = new HashMap(getBatchSize());

            while (!mapEntries.isEmpty()) {
                Iterator iterator = mapEntries.entrySet().iterator();
                while (iterator.hasNext() && batch.size() &lt; getBatchSize()) {
                    Map.Entry entry = (Map.Entry) iterator.next();
                    batch.put(entry.getKey(), entry.getValue());
                }
                storeBatch(batch);
                mapEntries.keySet().removeAll(batch.keySet());
                batch.clear();
            }
        }
    }

    @Override
    public void erase(Object key) {
        Object find = findEntity(key);
        if (find != null) {
            getHibernateTemplate().delete(find);
        }
    }

    private void storeBatch(Map batch) {
        getHibernateTemplate().saveOrUpdateAll(batch.values());
    }

    private Object findEntity(Object key) {
        Object object = null;
        if (key instanceof Integer) {
            object = getHibernateTemplate().get(getEntityName(), (Integer) key);
        }
        return object;
    }
}

Note that next to the write-max-batch-size setting, we can chunk the map passed by the write-behind thread by setting the batch-size. Note that smaller batches have a lighter load on the system, i.e., writing large batches to a database requires a larger transaction / rollback log in the database, more memory consumption by the JDBC driver and will also cause Coherence to consume more memory in the storage member. Data in the write-behind thread is stored in binary format and the map passed to storeAll is deserialized lazily, with the result that if a very large map is passed and deserialized, the garbage collector can introduce very long pauses.

An example Spring configuration looks as follows:

<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 id="cacheStore" class="model.util.readwrite.CustomCacheStore" scope="prototype">
        <property name="batchSize" value="256"/>
        <property name="hibernateTemplate" ref="hibernateTemplate"/>
    </bean>
    <bean id="cacheStoreProxy" parent="transactionTemplate">
        <property name="target" ref="cacheStore"/>
        <property name="proxyInterfaces" value="com.tangosol.net.cache.CacheStore"/>
    </bean>
    <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mappingResources">
            <list>
                <value>model/entities/Klant.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.c3p0.min_size">${connectionpool.minimum.size}</prop>
                <prop key="hibernate.c3p0.max_size">${connectionpool.maximum.size}</prop>
                <prop key="hibernate.c3p0.timeout">${connectionpool.timeout}</prop>
                <prop key="hibernate.c3p0.max_statements">${connectionpool.maximum.statements}</prop>
                <prop key="hibernate.c3p0.idle_test_period">${connectionpool.idle.period}</prop>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.current_session_context_class">${hibernate.current_session_context_class}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
            </props>
        </property>
    </bean>
    <bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
        <property name="driverType" value="${jdbc.driverClassName}"/>
        <property name="URL" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:spring-config.properties</value>
            </list>
        </property>
    </bean>
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    <bean id="transactionTemplate" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
          abstract="true">
        <property name="transactionManager" ref="transactionManager"/>
        <property name="transactionAttributes">
            <props>
                <prop key="store*">PROPAGATION_REQUIRED</prop>
                <prop key="erase*">PROPAGATION_REQUIRED</prop>
                <prop key="load*">PROPAGATION_SUPPORTS,readOnly</prop>
            </props>
        </property>
    </bean>
</beans>

To let Spring handle the transactions we have configured a cacheStoreProxy that uses a transactionTemplate and target this proxy to our cache store implementation. A target is an object that is being advised. Note that without AOP (aspect oriented programming) the target must handle its own transaction logic. A proxy is an object that is created after applying an advice to the target object. From a client viewpoint, the target object (pre-AOP) and the proxy object (post-AOP) are the same, i.e., the proxy class poses as the target bean, intercepting advised method calls and forwarding those calls to the target bean.

Integrating JMS

JMS resources are typically configured in an application server. Such resources are identified by using a unique name, a so-called JDNI name. In this case we need to retrieve resources that are not configured as Spring beans, but as ‘JNDI’ resources. We can use Spring’s JndiObjectFactoryBean for this purpose. The JndiObjectFactoryBean provides an abstraction layer to map JNDI objects to a bean.

If we were to retrieve the resources locally, i.e., the application is deployed on the application server where the resources are configured we can proceed as follows. First, we define a reference in, for example, the web.xml file

<resource-ref>
	<res-ref-name>jdbc/exampleDS</res-ref-name>
	<res-type>javax.sql.DataSource</res-type>
	<res-auth>Container</res-auth>
</resource-ref>

Subsequently, the Spring bean can be created as follows:

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
	<property name="jndiName" value="jdbc/exampleDS"/>
	<property name="resourceRef" value="true"/>
</bean>

When the resources have to be retrieved remotely, as in our case, we have to proceed as follows. First, we configure a JNDI template

<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
	<property name="environment">
		<props>
			<prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
			<prop key="java.naming.provider.url">t3://172.31.0.112:7002,172.31.0.112:7003</prop>
		</props>
	</property>
</bean>

Here, we connect to a WebLogic cluster. In this case we also need the weblogic.jndi.WLInitialContextFactory class in the classpath, which is provided by the wlclient.jar file. As we are planning to use WebLogic JMS, we also need the wljmsclient.jar in the classpath. To obtain the configured resources we can use the following

<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
	<property name="jndiTemplate" ref="jndiTemplate"/>
	<property name="jndiName" value="jms/ConnectionFactory"/>
</bean>
<bean id="destination" class="org.springframework.jndi.JndiObjectFactoryBean">
	<property name="jndiTemplate" ref="jndiTemplate"/>
	<property name="jndiName" value="jms/CompanyQueue"/>
</bean>

The WebLogic JMS configuration is the same as the one presented in the post Managing Failure Conditions in a WebLogic Environment. To use JMS in conjunction with Spring, we can resort to the JMSTemplate. To use JMSTemplate we need to configure it, i.e.,

<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
	<property name="connectionFactory" ref="connectionFactory"/>
	<property name="defaultDestination" ref="destination"/>
</bean>

Before, we add JMS to the cache store let us first test the set-up. In order to do this we create a sender

package model.util.jms;

import model.entities.Klant;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

import javax.jms.*;

public class JMSSender {

    private JmsTemplate jmsTemplate;

    public JmsTemplate getJmsTemplate() {
        return jmsTemplate;
    }

    public void setJmsTemplate(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    public void sendTextMessage() {
        getJmsTemplate().send(new MessageCreator(){
            public Message createMessage(Session session) throws JMSException {
                TextMessage message = session.createTextMessage();
                message.setText("Testing the JMS set-up one-two, one-two test");
                return message;
            }
        });
    }

    public void sendMessage(final Klant klant) {
        getJmsTemplate().send(new MessageCreator() {
            public Message createMessage(Session session) throws JMSException {
                ObjectMessage message = session.createObjectMessage();
                message.setObject(klant);
                return message;
            }
        });
    }
}

and a receiver

package model.util.jms;

import model.entities.Klant;
import javax.jms.*;

public class JMSReceiver implements MessageListener {

    public void onMessage(Message message) {
        if (message instanceof TextMessage) {
            TextMessage text = (TextMessage) message;
            try {
                message.acknowledge();
                System.out.println("received the following message: " + text.getText());
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }

        if (message instanceof ObjectMessage) {
            ObjectMessage objectMessage = (ObjectMessage) message;
            try {
                message.acknowledge();
                Klant person = (Klant) objectMessage.getObject();
                System.out.println("RECEIVED MESSAGE " + person);
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }
}

Note that the receiver looks very much like an equivalent of a message-driven bean, except for the MessageDriven annotation. In order for this to work we need to wire the receiver into a message listener container, i.e.,

<bean class="org.springframework.jms.listener.SimpleMessageListenerContainer">
	<property name="connectionFactory" ref="connectionFactory"/>
	<property name="destination" ref="destination"/>
	<property name="messageListener" ref="receiver"/>
</bean>
<bean id="sender" class="model.util.jms.JMSSender">
	<property name="jmsTemplate" ref="jmsTemplate"/>
</bean>
<bean id="receiver" class="model.util.jms.JMSReceiver"/>

Here, we also configured beans for the sender and the receiver. The test class looks as follows

package model.util.jms;

import model.entities.Klant;
import model.util.spring.SpringUtil;

import java.util.Random;

public class JMSTest {

    private Random generator = new Random();

    public static void main(String[] args) {
        JMSTest test = new JMSTest();

        JMSSender jmsSender = SpringUtil.getJMSSender();
        jmsSender.sendMessage(test.createKlant());
        System.out.println("done sending message");
    }

    private Klant createKlant() {
        int klantnummer = generateKlantNummer();

        Klant klant = new Klant();
        klant.setKlantnummer(klantnummer);
        klant.setNaam("Person" + klantnummer);
        klant.setAdres("Someware");
        klant.setStad("Else");
        klant.setProvincie("NL");
        klant.setPostcode("1234AB");
        klant.setGebied(1);
        klant.setTelefoonnummer("123-4567");
        klant.setReputatieNummer(1);
        klant.setKredietlimiet(Math.rint(generator.nextDouble() * 5000.0));
        klant.setCommentaar(Long.toString(Math.abs(generator.nextLong()), 36));

        return klant;
    }

    private Integer generateKlantNummer() {
        int klantnummer = generator.nextInt(10000);
        if (klantnummer == 0 || (klantnummer &gt;= 100 && klantnummer &lt;= 109)) {
            return 42;
        } else {
            return klantnummer;
        }
    }
}

When the JMS set-up is succesfully tested, we can continue with integrating JMS into the CustomCacheStore. We alter the CustomCacheStore such that a message is send when a customer is deleted. In this case the CustomCacheStore looks as follows

package model.util.readwrite;

import com.tangosol.net.cache.AbstractCacheStore;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.orm.hibernate3.HibernateTemplate;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class CustomCacheStore extends AbstractCacheStore {

    private Integer batchSize = 128;
    private HibernateTemplate hibernateTemplate;
    private JmsTemplate jmsTemplate;
    private String entityName;

    public Integer getBatchSize() {
        return batchSize;
    }

    public void setBatchSize(Integer batchSize) {
        this.batchSize = batchSize;
    }

    public HibernateTemplate getHibernateTemplate() {
        return hibernateTemplate;
    }

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

    public JmsTemplate getJmsTemplate() {
        return jmsTemplate;
    }

    public void setJmsTemplate(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    public String getEntityName() {
        return entityName;
    }

    public void setEntityName(String entityName) {
        this.entityName = entityName;
    }

    @Override
    public Object load(Object key) {
        return findEntity(key);
    }

    @Override
    public void store(Object key, Object value) {
        getHibernateTemplate().saveOrUpdate(value);
    }

    @Override
    public void storeAll(Map mapEntries) {
        if (getBatchSize() == 0 || mapEntries.size() &lt; getBatchSize()) {
            storeBatch(mapEntries);
        } else {
            Map batch = new HashMap(getBatchSize());

            while (!mapEntries.isEmpty()) {
                Iterator iterator = mapEntries.entrySet().iterator();
                while (iterator.hasNext() && batch.size() &lt; getBatchSize()) {
                    Map.Entry entry = (Map.Entry) iterator.next();
                    batch.put(entry.getKey(), entry.getValue());
                }
                storeBatch(batch);
                mapEntries.keySet().removeAll(batch.keySet());
                batch.clear();
            }
        }
    }

    @Override
    public void erase(Object key) {
        final Object find = findEntity(key);
        if (find != null) {
            getHibernateTemplate().delete(find);

            getJmsTemplate().send(new MessageCreator() {
                public Message createMessage(Session session) throws JMSException {
                    TextMessage message = session.createTextMessage();
                    message.setText("Deleted " + find.toString());
                    return message;
                }
            });
        }
    }

    private void storeBatch(Map batch) {
        getHibernateTemplate().saveOrUpdateAll(batch.values());
    }

    private Object findEntity(Object key) {
        Object object = null;
        if (key instanceof Integer) {
            object = getHibernateTemplate().get(getEntityName(), (Integer) key);
        }
        return object;
    }
}

The complete Spring config file looks as follows:

<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 id="cacheStore" class="model.util.readwrite.CustomCacheStore" scope="prototype">
        <property name="batchSize" value="256"/>
        <property name="hibernateTemplate" ref="hibernateTemplate"/>
        <property name="jmsTemplate" ref="jmsTemplate"/>
    </bean>
    <bean id="cacheStoreProxy" parent="transactionTemplate">
        <property name="target" ref="cacheStore"/>
        <property name="proxyInterfaces" value="com.tangosol.net.cache.CacheStore"/>
    </bean>
    <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mappingResources">
            <list>
                <value>model/entities/Klant.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.c3p0.min_size">${connectionpool.minimum.size}</prop>
                <prop key="hibernate.c3p0.max_size">${connectionpool.maximum.size}</prop>
                <prop key="hibernate.c3p0.timeout">${connectionpool.timeout}</prop>
                <prop key="hibernate.c3p0.max_statements">${connectionpool.maximum.statements}</prop>
                <prop key="hibernate.c3p0.idle_test_period">${connectionpool.idle.period}</prop>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.current_session_context_class">${hibernate.current_session_context_class}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
            </props>
        </property>
    </bean>
    <bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
        <property name="driverType" value="${jdbc.driverClassName}"/>
        <property name="URL" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:spring-config.properties</value>
            </list>
        </property>
    </bean>
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    <bean id="transactionTemplate" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
          abstract="true">
        <property name="transactionManager" ref="transactionManager"/>
        <property name="transactionAttributes">
            <props>
                <prop key="store*">PROPAGATION_REQUIRED</prop>
                <prop key="erase*">PROPAGATION_REQUIRED</prop>
                <prop key="load*">PROPAGATION_SUPPORTS,readOnly</prop>
            </props>
        </property>
    </bean>
    <!-- JMS configuration -->
    <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
        <property name="environment">
            <props>
                <prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
                <prop key="java.naming.provider.url">t3://172.31.0.112:7002,172.31.0.112:7003</prop>
            </props>
        </property>
    </bean>
    <bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="jndiTemplate"/>
        <property name="jndiName" value="jms/ConnectionFactory"/>
    </bean>
    <bean id="destination" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate" ref="jndiTemplate"/>
        <property name="jndiName" value="jms/CompanyQueue"/>
    </bean>
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="defaultDestination" ref="destination"/>
    </bean>
    <bean class="org.springframework.jms.listener.SimpleMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="destination" ref="destination"/>
        <property name="messageListener" ref="receiver"/>
    </bean>
    <bean id="sender" class="model.util.jms.JMSSender">
        <property name="jmsTemplate" ref="jmsTemplate"/>
    </bean>
    <bean id="receiver" class="model.util.jms.JMSReceiver"/>
</beans>

Test the set-up by using the Test class presented in the ‘basic set-up’ section.

References

[1] Coherence Integration Guide.


Spring and WebLogic: Messaging, WorkManagers and Timers

Say we want to deploy a Spring message driven POJO (MDP) on WebLogic. The problem here is that the threads which are initiated by the MDP are unmanaged. Every WebLogic server contains a thread queue in which work to be processed is added. Every piece of work is associated to an executethread, which processes the work to be done and is then ready to process other work. This thread management is implemented by the commonj api developed by IBM and BEA. An example of an implementation could be the following.

A single work queue, which is a wrapper around an instance of LinkedBlockingQueue. It handles a basic fault handling strategy, i.e., if an InterruptedException is catched when trying to add a new work item to the queue, the status of the work item is set to WORK_REJECTED.

package model.work;

import commonj.work.WorkException;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class SimpleWorkQueue {

    private BlockingQueue<DefaultWorkItem> workQueue = new LinkedBlockingQueue<DefaultWorkItem>();

    public SimpleWorkQueue() {
    }

    public boolean isEmpty() {
        return workQueue.isEmpty();
    }

    public boolean remove(Object object) {
        return workQueue.remove(object);
    }

    public void put(DefaultWorkItem workItem) throws InterruptedException {
        workQueue.put(workItem);
    }

    public DefaultWorkItem peek() {
        return workQueue.peek();
    }

    public DefaultWorkItem take() throws WorkException {
        try {
            return workQueue.take();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new WorkException(e);
        }
    }
}

The commonj WorkManager interface has four methods. The first two methods are for scheduling the work. Both methods, apart from the fact that one takes an WorkListener instance in order to get callback notifications when a work item changes state, work the same; they take work, wrap it in a WorkItem instance and add it to the queue. The methods return the created WorkItem instance, which gives the caller a reference to the pending Work for tracking or management. The two other methods waitForAll and waitForAny respectively block and wait until all Work has been completed or the method has timed out and returns immediately with a collection of all completed Work so far. The methods are implemented using the simplest thing that could possible work: a busy wait loop.

package model.work;

import commonj.work.Work;
import commonj.work.WorkEvent;
import commonj.work.WorkException;
import commonj.work.WorkItem;
import commonj.work.WorkListener;
import commonj.work.WorkManager;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;

public class SimpleWorkManager implements WorkManager {

    private SimpleWorkQueue workQueue;

    public SimpleWorkManager(SimpleWorkQueue workQueue) {
        this.workQueue = workQueue;
    }

    public WorkItem schedule(Work work) throws IllegalArgumentException {
        return schedule(work, null);
    }

    public WorkItem schedule(Work work, WorkListener workListener) throws IllegalArgumentException {
        DefaultWorkItem workItem = new DefaultWorkItem(work, null);
        try {
            workQueue.put(workItem);
        } catch (InterruptedException e) {
            workItem.setStatus(WorkEvent.WORK_REJECTED, new WorkException(e));
            Thread.currentThread().interrupt();
        }
        return workItem;
    }

    /**
     * Blocks until all specified WorkItems completed, or until the specified timeout.
     *
     * @param workItems
     * @param timeout
     * @return true is all items completed within the specified timeout value, false otherwise
     * @throws InterruptedException
     * @throws IllegalArgumentException
     */
    public boolean waitForAll(Collection workItems, long timeout) throws InterruptedException, IllegalArgumentException {
        long start = System.currentTimeMillis();
        do {
            boolean isAllCompleted = false;
            Iterator<WorkItem> iterator = workItems.iterator();
            while (iterator.hasNext() && !isAllCompleted) {
                int status = iterator.next().getStatus();
                System.out.println("een status: " + status);
                isAllCompleted = (status == WorkEvent.WORK_COMPLETED) || (status == WorkEvent.WORK_REJECTED);
                System.out.println(isAllCompleted);
            }
            if (isAllCompleted) {
                return true;
            }
            if (timeout == IMMEDIATE) {
                return false;
            }
            if (timeout == INDEFINITE) {
                continue;
            }
        } while ((System.currentTimeMillis() - start) < timeout);
        return false;
    }

    /**
     * blocks until any of the specified WorkItems complete until the specified timeout
     *
     * @param workItems
     * @param timeout
     * @return Collection of completed WorkItems
     * @throws InterruptedException
     * @throws IllegalArgumentException
     */
    public Collection waitForAny(Collection workItems, long timeout) throws InterruptedException, IllegalArgumentException {
        long start = System.currentTimeMillis();
        do {
            synchronized (this) {
                Collection<WorkItem> completed = new ArrayList<WorkItem>();
                Iterator<WorkItem> iterator = workItems.iterator();
                while (iterator.hasNext()) {
                    WorkItem workItem = iterator.next();
                    if (workItem.getStatus() == WorkEvent.WORK_COMPLETED || workItem.getStatus() == WorkEvent.WORK_REJECTED) {
                        completed.add(workItem);
                    }
                }
                if (!completed.isEmpty()) {
                    return completed;
                }
            }
            if (timeout == IMMEDIATE) {
                return Collections.EMPTY_LIST;
            }
            if (timeout == INDEFINITE) {
                continue;
            }
        } while ((System.currentTimeMillis() - start) < timeout);
        return Collections.EMPTY_LIST;
    }
}

We also need a Worker. This worker holds on to a SimpleWorkQueue reference. When the worker starts it uses a threadpool to spawn a number of worker threads that continuously grab and execute work items from the SimpleWorkQueue instance. Note that the queue is separating the WorkManager and his threadpool from the workers and their pools. The threadpool is an instance of the ExecutorService. During the execution of the work, work status is maintained by managing a flag in WorkItem.

package model.work;

import commonj.work.Work;
import commonj.work.WorkEvent;
import commonj.work.WorkException;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SimpleWorker implements Worker {

    private ExecutorService threadpool = Executors.newCachedThreadPool();
    private SimpleWorkQueue workQueue;
    private boolean isRunning = true;

    public SimpleWorker(SimpleWorkQueue workQueue) {
        this.workQueue = workQueue;
    }

    public void start() throws WorkException {
        while (isRunning) {
            final DefaultWorkItem workItem = workQueue.take();
            final Work work = workItem.getResult();
            this.threadpool.execute(new Runnable() {
                public void run() {
                    try {
                        workItem.setStatus(WorkEvent.WORK_STARTED, null);
                        work.run();
                        workItem.setStatus(WorkEvent.WORK_COMPLETED, null);
                    } catch (Throwable e) {
                        workItem.setStatus(WorkEvent.WORK_REJECTED, new WorkException(e));
                    }
                }
            });
        }
    }

    public void stop() {
        this.threadpool.shutdown();
        this.isRunning = false;
    }
}

Now, we have some basic knowledge of how a naive WorkManager environment is implemented. It gives you some idea how WebLogic handles the thread management.

Let us get back to the issue at hand, i.e., a Spring MDP running unmanaged in a WebLogic server. When we deploy an application to a WebLogic Server, the application is coupled to a default workmanager. When we want a managed Spring MDP in WebLogic we must also couple the MDP to, for example, the default workmanager. To this end we add the following entry in the web.xml file

<!-- default weblogic work manager -->
<resource-ref>
  	<res-ref-name>default</res-ref-name>
  	<res-type>commonj.work.WorkManager</res-type>
  	<res-auth>Container</res-auth>
  	<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

The resource-ref declares the default workmanager to the container. The container resolves the target during deployment, and makes it available in the local java:comp/env environment.

Spring has its own implementation of the commonj WorkManager (org.springframework.scheduling.commonj.WorkManagerTaskExecutor). To configure this workmanager using Spring, we can use the following bean configuration

<bean id="taskExecutor" class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">
  	<property name="workManagerName" value="java:comp/env/default"/>
  	<property name="resourceRef" value="true"/>
</bean>

Next, we need to configure a JMSTemplate for Spring, for example,

<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
	<property name="environment">
		<props>
			<prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
			<prop key="java.naming.provider.url">t3://localhost:7001</prop>
		</props>
	</property>
</bean>
<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
	<property name="jndiTemplate" ref="jndiTemplate"/>
	<property name="jndiName" value="jms/ConnectionFactory"/>
</bean>
<bean id="destination" class="org.springframework.jndi.JndiObjectFactoryBean">
	<property name="jndiTemplate" ref="jndiTemplate"/>
	<property name="jndiName" value="jms/Queue"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
	<property name="connectionFactory" ref="connectionFactory"/>
	<property name="defaultDestination" ref="destination"/>
</bean>

In the example above, we start with configuring a JNDI template, which connects to the global JNDI tree of the WebLogic Server. Using the JNDI template, we look up a connection factory and a destination. Using the connection factory and the destination we configure a JMS template. Now, we can use this template to create a JMS producer and a JMS receiver, for example

<bean class="org.springframework.jms.listener.SimpleMessageListenerContainer">
	<property name="connectionFactory" ref="connectionFactory"/>
	<property name="destination" ref="destination"/>
	<property name="messageListener" ref="receiver"/>
	<property name="taskExecutor" ref="taskExecutor"/>
</bean>
<bean id="sender" class="model.logic.JMSSender">
	<property name="jmsTemplate" ref="jmsTemplate"/>
</bean>
<bean id="receiver" class="model.logic.JMSReceiver"/>

The message listener container is a special bean that watches a JMS destination, waiting for a message to arrive. Once a message arrives, it retrieves the message and then passes it on to a MessageListener implementation by calling the onMessage method. The SimpleMessageListenerContainer is a simple message listener container. It works with a fixed number of JMS sessions and does not support transactions. In the example above the connectionFactory and destination properties are wired with the same connectionFactory and destination properties that we wired into JmsTemplate. As for the messageListener property, we have wired it with a reference to our MDP implementation so that the onMessage method will be invoked upon receipt of a message. The taskExecutor property is wired to the WorkManagerTaskExecutor bean, which references the WebLogic default workmanager. Theads issued by the simple message listener container are now handled by the default workmanager. The MDP implementation looks as follows

package model.logic;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

public class JMSReceiver implements MessageListener {
    public JMSReceiver() {
    }

    public void onMessage(Message message) {
        TextMessage text = (TextMessage)message;
        try {
            message.acknowledge();
            System.out.println("received the following message: " + text.getText());
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

We can also use Spring to send messages, for example,

package model.logic;

import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;

public class JMSSender implements Runnable {

    private JmsTemplate jmsTemplate;

    public JMSSender() {
    }

    public JmsTemplate getJmsTemplate() {
        return jmsTemplate;
    }

    public void setJmsTemplate(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    public void sendMessage() {
        getJmsTemplate().send(new MessageCreator(){
            public Message createMessage(Session session) throws JMSException {
                TextMessage message = session.createTextMessage();
                message.setText("blabla");
                return message;
            }
        });
    }

    public void run() {
        sendMessage();
    }
}

The sendMessage method is the centerpiece of JMSSender. It does nothing more than use the JmsTemplate‘s send method to send the message. When the send method is called, JmsTemplate will deal with obtaining a JMS connection and session and will send the message. The message itself is constructed using a MessageCreator, implemented here as an anonymous inner class. In MessageCreator‘s createMessage method, we simply assemble a JMS TextMessage and populate it with some text. The createMessage method is a callback method that JmsTemplate will use to construct the message that will be sent. The JmsTemplate is injected into the JMSSender using setter injection.

Assume, we next want that our messaging is running on a predefined time. For this we can also use the commonj api, but in this case not a WorkManager but a TimerManager. In the same manner as we injected a WorkManager in our environment, we can inject a TimerManager. Add the following entry in the web.xml file

<!-- default weblogic timer manager -->
<resource-ref>
	<res-ref-name>tm/default</res-ref-name>
	<res-type>commonj.timers.TimerManager</res-type>
	<res-auth>Container</res-auth>
	<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

If we want the messaging to run on some defined period, we can use the default Spring implementation, i.e., the ScheduledTimerListener, for example,

<bean id="timerListener" class="org.springframework.scheduling.commonj.ScheduledTimerListener">
	<property name="delay" value="10000"/>
	<property name="period" value="30000"/>
	<property name="runnable" ref="sender"/>
</bean>
<bean id="timerFactory" class="org.springframework.scheduling.commonj.TimerManagerFactoryBean">
	<property name="timerManagerName" value="java:comp/env/tm/default"/>
	<property name="resourceRef" value="true"/>
	<property name="scheduledTimerListeners">
		<list>
			<ref bean="timerListener"/>
		</list>
	</property>
</bean>

The run method, which we defined earlier in our JMSSender, defines what the runnable object is to do when it is run. In this case, it calls the sendMessage method. Spring’s ScheduledTimerListener defines how often a runnable object is to be run. In this case, we wait for 10 seconds and then run every 30 seconds to send a message to the JMS destination. We schedule the configured timerListener bean by confguring a TimerManagerFactoryBean by using the scheduledTimerListeners property.

If want the messaging to run on a predefined time, we have to extend the existing Spring classes in order to provide this functionality, for example,

package model.utils;

import java.util.Calendar;
import java.util.Date;
import org.springframework.scheduling.commonj.ScheduledTimerListener;

public class ScheduledDateTimerListener extends ScheduledTimerListener {

    private String timeToRun;
    private Date dateToRun;

    public ScheduledDateTimerListener() {
    }

    public String getTimeToRun() {
        return timeToRun;
    }

    public void setTimeToRun(String timeToRun) {
        Calendar calendar = Calendar.getInstance();

        String[] times = timeToRun.split(":");
        Integer hour = 0;
        Integer minutes = 0;
        Integer seconds = 0;
        if (times.length > 0) {
            hour = Integer.parseInt(times[0]);
        }
        if (times.length > 1) {
            minutes = Integer.parseInt(times[1]);

        }
        if (times.length > 2) {
            seconds = Integer.parseInt(times[2]);
        }

        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minutes);
        calendar.set(Calendar.SECOND, seconds);

        if (calendar.before(Calendar.getInstance())) {
            calendar.add(Calendar.DATE, 1);
        }

        setDateToRun(calendar.getTime());
    }

    public Date getDateToRun() {
        return dateToRun;
    }

    public void setDateToRun(Date dateToRun) {
        this.dateToRun = dateToRun;
    }
}

This extension allows us to set extra properties, such as time to run and date to run. To schedule this extension we also need to extend the TimerManagerFactoryBean, for example,

package model.utils;

import commonj.timers.TimerManager;
import org.springframework.scheduling.commonj.TimerManagerFactoryBean;

import javax.naming.NamingException;

public class DateTimerManagerFactoryBean extends TimerManagerFactoryBean {

    private ScheduledDateTimerListener[] scheduledDateTimerListeners;
    private TimerManager timerManager;
    private String timerManagerName;

    public DateTimerManagerFactoryBean() {
    }

    public ScheduledDateTimerListener[] getScheduledDateTimerListeners() {
        return scheduledDateTimerListeners;
    }

    public void setScheduledDateTimerListeners(ScheduledDateTimerListener[] scheduledDateTimerListeners) {
        this.scheduledDateTimerListeners = scheduledDateTimerListeners;
    }

    public TimerManager getTimerManager() {
        return timerManager;
    }

    public void setTimerManager(TimerManager timerManager) {
        this.timerManager = timerManager;
    }

    public String getTimerManagerName() {
        return timerManagerName;
    }

    @Override
    public void setTimerManagerName(String timerManagerName) {
        super.setTimerManagerName(timerManagerName);
        this.timerManagerName = timerManagerName;
    }

    @Override
    public void afterPropertiesSet() throws NamingException {
        super.afterPropertiesSet();

        if (getTimerManager() == null) {
            setTimerManager((TimerManager) lookup(getTimerManagerName(), TimerManager.class));
        }

        if (getScheduledDateTimerListeners() != null) {
            for (ScheduledDateTimerListener task: getScheduledDateTimerListeners()) {
                if (task.getPeriod() > 0) {
                    if (task.isFixedRate()) {
                        getTimerManager().scheduleAtFixedRate(task.getTimerListener(), task.getDateToRun(), task.getPeriod());
                    } else {
                        getTimerManager().schedule(task.getTimerListener(), task.getDateToRun(), task.getPeriod());
                    }
                } else {
                    getTimerManager().schedule(task.getTimerListener(), task.getDateToRun());
                }
            }
        }
    }
}

Just as we configured to run our messaging on a defined interval we can configure the scheduling using the classes presented above, for example,

<bean id="dateTimerListener" class="model.utils.ScheduledDateTimerListener">
	<property name="timeToRun" value="13:05"/>
	<property name="period" value="3600000"/>
	<property name="fixedRate" value="true"/>
	<property name="runnable" ref="sender"/>
</bean>
<bean id="dateTimerFactory" class="model.utils.DateTimerManagerFactoryBean">
	<property name="timerManagerName" value="java:comp/env/tm/default"/>
	<property name="resourceRef" value="true"/>
	<property name="scheduledDateTimerListeners">
		<list>
			<ref bean="dateTimerListener"/>
		</list>
	</property>
</bean>

Now the messaging starts at five past one and runs every hour.

References

[1] Walls, “Spring in Action”, Manning, 2008. All you ever wanted to know about Spring (also a good reference when you are going for your Spring certification).
[2] Spring Reference Documentation.
[3] The Timer and Work Manager API.


  • Testimonials

  • RSS Middleware Magic – JBoss

  • Receive FREE Updates


    FREE Email updates of our new posts Enter your email address:



  • Magic Archives

  • Sitemeter Status

  • ClusterMap 7-Nov-2011 till Date

  • ClusterMap 6-Nov-2010 till 7-Nov-2011

  • Copyright © 2010-2012 Middleware Magic. All rights reserved. | Disclaimer