» tagged pages
» logout
Spring
Return to Spring

Spring's corner

(or Cancel)

(Editing anonymously: to be credited for your changes, login or register a new account)

other page actions:

Tags Applied to this Topic

1 person has tagged this page:

Thoughts and articles on Spring

Tuesday, July 17, 2007

Integrate P6Spy with Spring



P6Spy is a tool to debug JDBC interaction with a database. It's a wrapper of all JDBC elements ( Connection, PreparedStatement, ResultSet... ) and it has a powerful feature in order to log all informations about those interactions.

JDBC wrapper is described in the "Java Performance Tuning" book of Jack Shirazi ( O'Reilly) in the chapter 16.

All elements wrappers have a constructor with the element to wrap. We can use it but there is another mode for datasource. This last mode must be used to wrap a datasource defined in an application server for example.

However since we can manage our objects ( beans ) in Spring ( and datasources too ), it's possible to add a P6Spy datasource and link it with the real datasource with constructor injection.

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> <bean id="myDataSourceTarget" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName"> <value>org.hsqldb.jdbcDriver</value> </property> <property name="url"> <value>jdbc:hsqldb:hsql://localhost:9001</value> </property> <property name="username"><value>sa</value></property> <property name="password"><value></value></property> </bean>
<bean id="myDataSource" class="com.p6spy.engine.spy.P6DataSource" destroy-method="close"> <constructor-arg> <ref local="myDataSourceTarget"/> </constructor-arg> </bean>
</beans>

Moreover a p6spy.log file must be add to the classpath of the application to specify the location of the log file.

module.log=com.p6spy.engine.logging.P6LogFactory
executionthreshold= outagedetection=false outagedetectioninterval= filter=false include = exclude = sqlexpression = autoflush = true dateformat= includecategories= excludecategories=info,debug,result,batch
stringmatcher= stacktraceclass=
reloadproperties=false reloadpropertiesinterval=60
useprefix=false
appender=com.p6spy.engine.logging.appender.FileLogger logfile = c:/spy.log
append=true
log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout log4j.appender.STDOUT.layout.ConversionPattern=p6spy - %m%n
log4j.logger.p6spy=INFO,STDOUT

The output can be graphically view with a tool like Iron Track SQL.

The advantages of this solution are the following:

  • It isn't necessary to modify the configuration of the application server datasource in order to integrate P6Spy.
  • The use of P6Spy is much easier. No deep knowledge of the format of the P6Spy configuration file is required ( only specify the location of log file ).
  • Tuesday, July 17, 2007

    My blog has moved...

    I have moved my old blog on this blog with a new skin. You can have access to my old entries at the following url: http://templth.blogspot.com

    Tuesday, July 17, 2007

    JMX notifications with Spring

    The Spring framework offers a great support of JMX. The aims of this support are:

    • automatically convert simple beans into MBeans
    • automatically register simple beans and MBeans declaratively
    • configure an embedded JMX server
    • configure JMX connectors to access to the components of the agent layer

    At this time, the support doesn't include JMX notifications but it's planned for the version 1.3RC2. See the issue SPR-680 in JIRA: http://opensource2.atlassian.com/projects/spring/browse/SPR-680

    I have developped some code to implement this issue. Its aims are:

    • provide a way to add/remove JMX listeners on registred MBeans based on their object names
    • provide a way to add/remove JMX listeners on simple beans and MBean exported on the JMX server with Spring facilities.
    • offer an abstraction to allow bean or MBean exported with to send notifications

    Add/remove JMX listeners on registered MBeans

    The aim of this part is to add/remove listeners on MBean not registered with Spring facilities. The common example is to listen events triggered by the MBean server delegate. This entity sends notifications on register/unregister MBean events. The following listing shows how to configure it.

    <bean id="delegateListeners" class="org.springframework.jmx.export.notifier.NotifierFactoryBean">
      <property name="server"><ref local="mbeanServer"/></property>
      <property name="objectName">
        <value>
          JMImplementation:type=MBeanServerDelegate
        </value>
      </property>
      <property name="notificationListeners">
        <ref local="listener"/>
      </property>
    </bean>
    <bean id="listener" class="TestNotificationListener"/>

    The class testNotificationListener is a classic JMX notification listener as shown in the following listing:

    public class TestNotificationListener
                     implements NotificationListener {
      public void handleNotification(
                     Notification notification, Object handback) {
        System.out.println("Notification received.");
        System.out.println(" -> "+notification);
      }
    }
    

    The listener receives the following notifications for example:

    Notification received.
     -> javax.management.MBeanServerNotification
              [source=JMImplementation:type=MBeanServerDelegate]
                           [type=JMX.mbean.registered][message=]
    Notification received.
     -> javax.management.MBeanServerNotification
              [source=JMImplementation:type=MBeanServerDelegate]
              [type=JMX.mbean.unregistered][message=]
    

    Add/remove JMX listeners on MBeans registered with Spring

    The support distinguishes two possibilities according to the kind of instance to export.

    First the bean ot export is a simple bean not tied with JMX. In this case, the JMX support of Spring uses model MBean to convert the bean into an MBean according to different strategies to know attributes and methods to expose. The RequiredModelMBean already implements the NotificationBroadcaster, so there is nothing to do, but the listeners must be added not on the bean but on the created model MBean.

    Secondly the bean is a MBean (so tied with JMX). In this case, the support looks if the MBean implements the NotificationBroadcaster. This JMX interface allows MBean to register and unregister notification listeners.

    If not, AOP is used to add this interface to the bean with the method introduction feature. The implementation of this interface is the GenericBroadcaster class based on the NotificationBroadcasterSupport of JMX.

    The following listing shows an example of use in this case.

    <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
      <property name="beans">
        <map>
          <entry key="bean:name=testBean1"
                    value-ref="testBean"/>
          <entry key="bean:name=testBean2"
                    value-ref="testSimpleBean"/>
        </map>
      </property>
      <property name="notificationListeners">
        <ref local="listener"/>
      </property>
      <property name="server" ref="mbeanServer"/>
    </bean>
    <bean id="listener" class="TestNotificationListener"/>

    Send notifications from simple beans and MBeans registered with Spring

    To send a notification, the simple bean or the MBean needs an abstraction. This abstraction must just have a method to send a notification. I define the Notifier interface as following:

    public interface Notifier {
      void notify(NotificationCreator creator,Object handback);
    }
    

    One of the challenge is to give an instance of this interface. The simple bean or MBean must tell the JMX support that it can accept this by implementing the NotifierAware interface. It works like the other *Aware interfaces (ApplicationContextAware, BeanFactoryAware) in Spring. If the support detects this interface, it will call the method setNotifier on it.

    public interface NotifierAware {
      void setNotifier(Notifier notifier);
    }
    

    The following listing shows an example to send a notification.

    public class MyBean
      public void test() {
        notifier.notify(new NotificationCreator() {
          public Notification createNotification() {
            return new Notification("test",this,0);
          }
        },null);
      }
    public void setNotifier(Notifier notifier) { System.out.println("TestSimpleBean.setNotifier"); this.notifier=notifier; } }

    Note: I have a doubt about the utility of the NotificationCreator which offers a callback to create the Notification. As a matter of fact, the creation of a notification instance is just a new... I'm thinking of removing it.

    Improve the support

    An improvement could be the support of filter for notification and the management of the handback instance...

    To be continued ;-)

    Tuesday, July 17, 2007

    JMX notifications with Spring (2)

    The second part of the thread describe the end of the support of JMX notifications in Spring. Like the previous one, it describes the patch I have written to address the issue SPR-680 in JIRA.

    See the second zip file (SpringJMX_Notification_v1.1.zip) on the issue for the implementation of this patch.

    Support of filters

    When a JMX notification listener is added to an MBean, you can pass a filter to select notifications the listener will accept. In our case, we use the class NotificationFilterSupport which implements NotificationFilter and allow configure the allow and deny of notifications types.

    public class NotificationListenerSupport {
      ...
      public synchronized boolean isNotificationEnabled(
                           Notification notification) {...}
      public synchronized void enableType(String type)
                   throws IllegalArgumentException {...}
      public synchronized void disableType(String type) {...}
      public synchronized void disableAllTypes() {...}
      public synchronized Vector getEnabledTypes() {...}
      ...
    }
    

    To associate filters with listeners on the MBeanExporter class, you need to set the notificationFilters property which tokens are delimited by the character ','. If the element starts with the character '+', the nofication type is allowed and if it starts with '-', the type is denied. The following listing shows an example of use.

    <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
      <property name="beans">
        ...
      </property>
      <property name="notificationListeners">
        <list>
          <ref local="listener"/>
        </list>
      </property>
      <property name="notificationFilters">
        <value>DENY_ALL_TYPES,+test</value>
      </property>
    </bean>
    

    Note: This feature is supported on the NotifierFactoryBean class too.

    Support of handback

    Handback is an object specified on the call of addNotificationListener which is then given to the listener when a notification is triggered. The patch supports now this feature with the handback property of the MBeanExporter class. The following listing shows an example of use.

    <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
      <property name="beans">
        ...
      </property>
      <property name="notificationListeners">
        <list>
          <ref local="listener"/>
        </list>
      </property>
      <property name="notificationFilters">
        <value>DENY_ALL_TYPES,+test</value>
      </property>
      <property name="handback" value="test handback"/>
    </bean>
    

    Note: This feature is supported on the NotifierFactoryBean class too.

    Tuesday, July 17, 2007

    Jencks in action

    The aim of this article is to describe the use of Jencks (http://jencks.org). It is based on the version 1.1.1 of the project.

    This project allows application to use the transaction and connector modules with the JCA support of Spring in order to use JCA in a managed mode outside a J2EE application server. It allows to develop more lightweight applications and to embed XA features into every applications even if they are not deployed in an application server.

    JCA support of Spring

    The JCA support of Spring provides a dedicated FactoryBean implementation, LocalConnectionFactoryBean, to configure a JCA connector in a non managed mode. You can too use it to configure a connector in a managed mode if you specify an implementation of the JCA ConnectionManager interface in addition to the ManagedConnectionFactort as described in the following code.

    <bean id="connectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean">
      <property name="managedConnectionFactory"><ref local="managedConnectionFactory"/></property>
      <property name="connectionManager"><ref local="connectionManager"/></property>
    </bean>
    

    Note that the LocalConnectionFactoryBean class can be used to expose different interfaces like the JMS ConnectionFactory, the JDBC DataSource, the Hibernate SessionFactory, of course the JCA ConnectionFactory...

    When using this feature, you are now able to add your resources in the context of global transactions and use them with JTA.

    Jencks

    Jencks is very close to the Geronimo and Spring projects. As a matter of fact, it provides dedicated FactoryBean to configure resources of the connector and transaction modules of Geronimo.

    The first step to use Jencks is to configure the transaction module as following.

    <bean id="connectionTracker"
          class="org.apache.geronimo.connector.outbound.connectiontracking.ConnectionTrackingCoordinator"/>
    <bean id="transactionManagerImpl" class="org.jencks.factory.TransactionManagerFactoryBean"> <property name="defaultTransactionTimeoutSeconds" value="600"/> <property name="transactionLog"> <bean class="org.apache.geronimo.transaction.log.UnrecoverableLog"/> </property> </bean>
    <bean id="transactionContextManager" class="org.jencks.factory.TransactionContextManagerFactoryBean"> <property name="transactionManager" ref="transactionManagerImpl"/> </bean>
    <bean id="userTransaction" class="org.jencks.factory.UserTransactionFactoryBean"> <property name="transactionContextManager" ref="transactionContextManager"/> <property name="connectionTrackingCoordinator" ref="connectionTracker"/> </bean>

    The connector module will use the entities in order to be able to use global transactions.

    The next step is to configure the ConnectionManager implementation of Geronimo. It provides a pooling mechanism and a contract with the transaction manager. So you must configure a ConnectionManager for each factories (DataSource, SessionFactory, ConnectionManager...).

    The configuration of the XA JMS ConnectionFactory of ActiveMQ is described in the following code. It is based on the ActiveMQ JCA connector. Firstly, you must configure the ConnectionManager and then the connector using it. Note that the configuration of ConnectionManager is similar for every connector.

    <bean id="transactionSupport"
          class="org.jencks.factory.XATransactionFactoryBean">
      <property name="useTransactionCaching" value="true"/>
      <property name="useThreadCaching" value="false"/>
      </property>
    </bean>
    <bean id="poolingSupport" class="org.jencks.factory.SinglePoolFactoryBean"> <property name="maxSize" value="2"/> <property name="minSize" value="1"/> <property name="blockingTimeoutMilliseconds" value="60"/> <property name="idleTimeoutMinutes" value="60"/> <property name="matchOne" value="true"/> <property name="matchAll" value="true"/> <property name="selectOneAssumeMatch" value="true"/> </bean>
    <bean id="jmsConnectionManager" class="org.jencks.factory.ConnectionManagerFactoryBean"> <property name="transactionSupport" ref="transactionSupport"/> <property name="poolingSupport" ref="poolingSupport"/> <property name="transactionContextManager" ref="transactionContextManager"/> <property name="connectionTracker" ref="connectionTracker"/> </bean>

    Then you need to configure the connector basing the ConnectionManager previously configured. Here is a sample with the connector of ActiveMQ. In this case, you can inject the JMS ConnectionFactory configured which is internally XA compliant. So it can participate in a 2PC transaction.

    <bean id="jmsResourceAdapter" class="org.activemq.ra.ActiveMQResourceAdapter">
      <property name="serverUrl" value="tcp://localhost:61616"/>
      </bean>
    <bean id="jmsManagedConnectionFactory" class="org.activemq.ra.ActiveMQManagedConnectionFactory"> <property name="resourceAdapter" ref="jmsResourceAdapter"/> </bean>
    <bean id="jmsConnectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean"> <property name="managedConnectionFactory" ref="jmsManagedConnectionFactory"/> <property name="connectionManager" ref="jmsConnectionManager"/> </bean>

    Transaction demarcation with Spring

    With the use of Jencks, you can manage transactions in your application normally with the classic support of Spring. In this case, the implementation of the PlatformTransactionManager interface to use is JtaTransactionManager.

    For more information, see the chapter Transaction management in the reference documentation of Spring. The following code shows how to configure the JtaTransactionManager with the previous configured beans.

    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
      <property name="userTransaction" ref="userTransaction"/>
      <property name="transactionManager" ref="transactionManagerImpl"/>
    </bean>
    

    In this howto, we have described the way to use Jencks, ActiveMQ and Spring to make global transactions with JCA and Geronimo outside the application server. The article is focused on the outbound communication of JCA. As the ActiveMQ connector is 1.5 compliant, you can use Jencks with inbound communication. I will describe this feature in a next howto.

    Tuesday, July 17, 2007

    Use the JMS support of Spring with Joram

    The aim of this entry is to describe the way to use the JMS support of Spring in order to develop Java/J2EE applications based on the JMS provider Joram.

    Firstly, we will describe the way to configure the ConnectionFactory of Joram in a context of Spring. Then, we will show how to handle the destinations with both JNDI and administration API of Joram. Finally, we will see how to use the JmsTemplate class of Spring in order to send and receive JMS messages basing on Joram.

    Configuration of the ConnectionFactory instance

    The first thing to do is to configure the ConnectionFactory of Joram in order to inject it in the JmsTemplate class of Spring. Joram offers several implementations of the JMS interface ConnectionFactory. We will see the configurations of the one based on tcp and an other used for embedded server.

    Firstly, if you need to access a Joram server with tcp, you must use the TcpConnectionFactory class. This class can be configured as a Bean as following:

    <bean id="connectionFactory"
         class="org.objectweb.joram.client.jms.tcp.TcpConnectionFactory">
        <constructor-arg index="0" value="tcp://localhost/"/>
        <constructor-arg index="1" value="16010"/>
    </bean>
    

    In the case of the class LocalConnectionFactory, you need to use a static factory method in order to instanciate a ConnectionFactory of this type.

    ConnectionFactory connectionFactory=LocalConnectionFactory.create("root","root");
    

    For this class, you can choose to use the support of factory method of Spring or develop a custom FactoryBean as following:

    public class LocalConnectionFactoryBean
                      implements FactoryBean,InitializingBean {
        private ConnectionFactory connectionFactory;
    public Object getObject() throws Exception { return connectionFactory; }
    public Class getObjectType() { return ConnectionFactory.class; }
    public boolean isSingleton() { return true; }
    public void afterPropertiesSet() throws Exception { this.connectionFactory=LocalConnectionFactory.create(); } }

    This class will be configured in Spring as following:

    <bean id="connectionFactory"
             class="test.joram.LocalConnectionFactoryBean"/>
    

    Note that you can too choose to use the JndiObjectFactoryBean in order to get an instance of a ConnectionFactory from JNDI. The following code shows how to configure this strategy:

    <bean id="connectionFactory" class="...JndiObjectFactoryBean">
        <property name="jndiName" value="cnf"/>
    </bean>
    

    Working with destintations

    After having configured your JMS ConnectionFactory for Joram, the strategy to resolve the destinations must be configured. As a matter of fact, the JmsTemplate of Spring can be used both with a parameter 'destination' of type Destionation or a parameter 'destinationName' of type String.

    In the first case, the application is entirely responsible to get the instance of the destination. You can use both JNDI or administration API of Joram. Here is an example of the latter:

    (...)
    JmsTemplate template=createTemplate();
    List destinations=AdminModule.getDestinations(); Destination destination=null; for(Iterator i=destinations.iterator();i.hasNext();) { Destination tmpDestination=(Destination)i.next(); if( !isQueue(destination) ) { continue; }
    if( destinationName.equals(destination.getAdminName()) ) { destination=tmpDestination; } }
    template.send(destination,new MessageCreator() { public Message createMessage(Session session) throws JMSException { (...) return (...); } });

    In the second case, the JMS support of Spring delegates the task to get the destination instance basing on the name of destination to an instance of the interface DestinationResolver. There are two implementations provides by the support: DynamicDestinationResolver (based on the method createQueue and createTopic of JMS API) and JndiDestionationResolver (based on Jndi).

    By defaut, the template uses the first one, but you can provide your own one with the method setDestinationResolver of this class.

    Here is a custom one for Joram named JoramDestinationResolver which looks for the destination thanks to the administration API of the provider. If it doesn't exist, the class uses the same API in order to create it.

    public class JoramDestinationResolver
                         implements DestinationResolver,InitializingBean {
        private static final Object JORAM_QUEUE_TYPE = "queue";
        private static final Object JORAM_TOPIC_TYPE = "topic";
    private JoramAdmin admin; private String hostName; private int port; private String userName; private String password;
    public Destination resolveDestinationName( Session session,String destinationName, boolean pubSubDomain) throws JMSException { List destinations = doGetDestinations(); for(Iterator i=destinations.iterator();i.hasNext();) { Destination destination=(Destination)i.next(); if( !isPubSubDomain(destination,pubSubDomain) ) { continue; }
    if( destinationName.equals(destination.getAdminName()) ) { return destination; } }
    return doCreateDestination(destinationName,pubSubDomain); }
    private Destination doCreateDestination( String destinationName, boolean pubSubDomain) { try { Destination destination=null; if( !pubSubDomain ) { destination=(Destination)admin.createQueue(destinationName); } else { destination=(Destination)admin.createTopic(destinationName); } destination.setFreeReading(); destination.setFreeWriting(); return destination; } catch(AdminException ex) { throw new JoramAdminException( "Unable to create the destination"+ " with the name "+destinationName,ex); } catch (ConnectException ex) { throw new JoramAdminException( "Unable to create the destination with"+ " the name "+destinationName,ex); } }
    private List doGetDestinations() { try { List destinations=AdminModule.getDestinations(); return destinations; } catch(Exception ex) { throw new JoramAdminException("Unable to get the"+ " list of destinations",ex); } }
    private boolean isPubSubDomain( Destination destination, boolean pubSubDomain) { if( !pubSubDomain && JORAM_QUEUE_TYPE.equals(destination.getType()) ) { return true; }
    if( pubSubDomain && JORAM_TOPIC_TYPE.equals(destination.getType()) ) { return true; }
    return false; }
    public void afterPropertiesSet() throws Exception { if( hostName==null || port==0 ) { throw new IllegalArgumentException( "Both hostName and port are required"); }
    if( userName==null || password==null ) { throw new IllegalArgumentException( "Both userName and password are required"); }
    admin=new JoramAdmin(hostName,port,userName,password,60); }
    public String getHostName() { return hostName; }
    public void setHostName(String hostName) { this.hostName = hostName; }
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
    public int getPort() { return port; }
    public void setPort(int port) { this.port = port; }
    public String getUserName() { return userName; }
    public void setUserName(String userName) { this.userName = userName; } }

    Sending JMS messages using the JoramDestinationResolver class

    This DestinationResolver implementation can be used as following in order to send JMS messages with the JmsTemplate class.

    (...)
    JmsTemplate template=createTemplate();
    JoramDestinationResolver resolver=new JoramDestinationResolver();
    resolver.setHostName("localhost");
    resolver.setPort(16010);
    resolver.setUserName("root");
    resolver.setPassword("root");
    resolver.afterPropertiesSet();
    template.setDestinationResolver(resolver);
    template.send(destinationName,new MessageCreator() { public Message createMessage(Session session) throws JMSException { (...) return (...); } });

    Receiving JMS messages using the JoramDestinationResolver

    Since its version 2.0, Spring offers support for JMS asynchronous communications with the classes SimpleMessageListenerContainer and ServerSessionMessageListenerContainer which must be configured with an instance of the class MessageListener of the JMS specification.

    These two classes support the mechanism based on the DestinationResolver interface in order to get an instance of a destination using its name.

    Here is an example based on a JMS MessageListener:

    <bean id="myJmsListener" class="test.joram.MyJmsListener"/>
    <bean id="destinationResolver" class="joram.JoramDestinationResolver"> <property name="hostName" value="localhost"/> <property name="port" value="16010"/> <property name="userName" value="root"/> <property name="password" value="root"/> <bean>
    <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="connectionFactory" ref="connectionFactory"/> <property name="destinationResolver" ref="destinationResolver"/> <property name="destinationName" value="test.queue"/> <property name="messageListener" ref="myJmsListener"/> </bean>

    Tuesday, July 17, 2007

    Book: Spring par la pratique

    I'm pleased to announce the publishing of the book "Spring par la pratique" (Eyrolles).

    I have co-written this book with Julien Dubois and Jean-Philippe Retaillé. Rod Johnson has written a great preface.

    The book is the first book dedicated to the Spring framework written in french. It has been added in the list of books on the website of the framework. See the following urls: http://www.springframework.org/books and http://www.springframework.org/bookreview

    You can have more details on the book on the website of Eyrolles:
    summary, contents and sample chapters. You can reach the page of the book and download the sample chapters at the following url:
    http://www.eyrolles.com/Accueil/Livre/9782212117103/

    You can buy online this book on the following sites:

    Tuesday, July 17, 2007

    Spring at ECOOP 2006 in Nantes

    Next week, Rob Harrop and Adryan Colyer will make a presentation of Spring AOP during ECOOP 2006 in Nantes:

    "This tutorial provides an introduction to aspect-oriented programming using the Spring framework and AspectJ. Attendees will understand the principles behind AOP, and where it fits in enterprise application development. We demonstrate how to write aspects using the Spring framework, exploiting the AspectJ pointcut language. The @AspectJ (annotation based) style of aspect declaration supported by AspectJ 5 will be explained, including support for using such aspects with the Spring AOP framework. Finally we look at the AspectJ language itself, how it goes beyond the capabilities of Spring AOP, and how to get started with some quick wins on your own projects."

    For more details, see the page decribing this event: http://www.emn.fr/x-info/ecoop2006/Tid7.html

    Tuesday, July 17, 2007

    Jencks namespace

    Jencks is a project hosted on the codehaus site which allows to embed the transaction and connection managers of Geronimo in every applications.

    In order to simply the configuration of the two different managers, we have developped a dedicated namespace handler for Spring called Jencks. It allows applications to use two tags, transactionManager and connectionManager, which will be described in the following sections.

    The XML grammar of these tags is described in the spring-jencks.xsd file. The content of this file is the following:

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <xsd:schema xmlns="http://www.springframework.org/schema/jencks" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans" targetNamespace="http://www.springframework.org/schema/jencks" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xsd:import namespace="http://www.springframework.org/schema/beans"/>
    <xsd:element name="transactionManager"> <xsd:complexType> <xsd:sequence> <xsd:element name="transactionLog" type="transactionLogType" minOccurs="0" maxOccurs="1" /> </xsd:sequence> <xsd:attribute name="id" type="xsd:ID" /> <xsd:attribute name="userTransactionId" type="xsd:string" /> <xsd:attribute name="transactionContextManagerId" type="xsd:string" /> <xsd:attribute name="connectionTrackerId" type="xsd:string" /> <xsd:attribute name="defaultTransactionTimeoutSeconds" type="xsd:string" /> </xsd:complexType> </xsd:element>
    <xsd:element name="connectionManager"> <xsd:complexType> <xsd:sequence> <xsd:element name="transactionSupport" type="transactionSupportType" minOccurs="0" maxOccurs="1" /> <xsd:element name="poolingSupport" type="poolingSupportType" minOccurs="0" maxOccurs="1" /> </xsd:sequence> <xsd:attribute name="id" type="xsd:ID" /> <xsd:attribute name="transactionContextManager-ref" type="xsd:string" /> <xsd:attribute name="connectionTracker-ref" type="xsd:string" /> </xsd:complexType> </xsd:element>
    <xsd:complexType name="transactionLogType"> <xsd:sequence> <xsd:element ref="beans:bean" /> </xsd:sequence> </xsd:complexType>
    <xsd:complexType name="transactionSupportType"> <xsd:attribute name="useTransactionCaching" type="xsd:boolean" default="true" /> <xsd:attribute name="useThreadCaching" type="xsd:boolean" default="false" /> </xsd:complexType>
    <xsd:complexType name="poolingSupportType"> <xsd:attribute name="maxSize" type="xsd:int" default="2" /> <xsd:attribute name="minSize" type="xsd:int" default="1" /> <xsd:attribute name="blockingTimeoutMilliseconds" type="xsd:int" default="60" /> <xsd:attribute name="idleTimeoutMinutes" type="xsd:int" default="60" /> <xsd:attribute name="matchOne" type="xsd:boolean" default="true" /> <xsd:attribute name="matchAll" type="xsd:boolean" default="true" /> <xsd:attribute name="selectOneAssumeMatch" type="xsd:boolean" default="true" /> </xsd:complexType> </xsd:schema>

    Note that this namespace need the version 2.0 M4 of Spring.

    Installation

    In order to use this namespace handler in Spring, we need to add two files in the META-INF directory of your project.

    Firstly, the spring.handlers file specifies the name of implementation of NamespaceHandler. The follwing code describes the content of this file:

    http\://www.springframework.org/schema/jencks=org.springframework.jca.config.JencksNamespaceHandler
    

    Secondly, the spring.schemas file specifies the location of the xsd file in the classpath. The follwing code describes the content of this file:

    http\://www.springframework.org/schema/jencks=org/springframework/jca/config/spring-jencks.xsd
    

    Configuration of the transaction manager

    The tag transactionManager is used to configuration the JTA transaction manager of Geronimo. It internally creates four beans:

    • Transaction manager (identified by the value of the id attribute)
    • Transaction context manager (identified by the value of the transactionContextManagerId attribute)
    • User transaction (identified by the value of the userTransactionId attribute)
    • Connection tracker (identified by the value of the connectionTrackerId attribute)

    The following code is an example of use of this tag in a application context of Spring:

    <jencks:transactionManager id="transactionManager"
                   userTransactionId="userTransaction"
                   transactionContextManagerId="transactionContextManager"
                   connectionTrackerId="connectionTracker"
                   defaultTransactionTimeoutSeconds="600">
    <jencks:transactionLog> <bean class="org.apache.geronimo.transaction.log.UnrecoverableLog"/> </jencks:transactionLog>
    </jencks:transactionManager>

    Configuration of the connection manager

    The tag connectionManager is used to configuration the JCA connection manager of Geronimo. It can be used in order to configure a connector for outbound communications. It internally creates one bean:

    • Connection manager (identified by the value of the id attribute)

    This tag is based on entites configured by the tag described in the previous section:

    • Transaction context manager (referenced by the value of the transactionContextManager-ref attribute)
    • Connection tracker (referenced by the value of the connectionTracker-ref attribute)

    The following code is an example of use of this tag in a application context of Spring:

    <jencks:connectionManager id="connectionManager"
              transactionContextManager-ref="transactionContextManager"
              connectionTracker-ref="connectionTracker">
    <jencks:transactionSupport useTransactionCaching="true" useThreadCaching="false"/>
    <jencks:poolingSupport maxSize="2" minSize="2" blockingTimeoutMilliseconds="60" idleTimeoutMinutes="60" matchOne="true" matchAll="true" selectOneAssumeMatch="true"/>
    </jencks:connectionManager>

    Tuesday, July 17, 2007

    Book: JavaScript pour le Web 2.0

    I'm pleased to announce the publishing of the book "JavaScript pour le Web 2.0" (Eyrolles) which I have co-written this book with Arnaud Gougeon.

    The book describes the use of JavaScript and different librairies in order to develop rich internet application or web site with a rich user interface.

    It covers all the aspects of the JavaScript language (basis, object oriented programming, dom, ajax) and its use and its interactions with (X)HTML and CSS in a web page.

    It also covers in depth several JavaScript libraries like Prototype, Dojo, script.aculo.us, Rialto, Behaviour.

    To finish, it deals with additional tools in order to develop and test JavaScript applications.

    A project has been created for this book and can be reached at the following url: http://jsweb2.sourceforge.net/.

    You can have more details on the book on the website of Eyrolles:
    summary, contents and sample chapters. You can reach the page of the book and download the sample chapters at the following url:
    http://www.eyrolles.com/Accueil/Livre/9782212117103/

    You can buy online this book on the following sites:

    Saturday, January 13, 2007

    Book: JavaScript pour le Web 2.0

    I'm pleased to announce the publishing of the book "JavaScript pour le Web 2.0" (Eyrolles) which I have co-written this book with Arnaud Gougeon.

    The book describes the use of JavaScript and different librairies in order to develop rich internet application or web site with a rich user interface.

    It covers all the aspects of the JavaScript language (basis, object oriented programming, dom, ajax) and its use and its interactions with (X)HTML and CSS in a web page.

    It also covers in depth several JavaScript libraries like Prototype, Dojo, script.aculo.us, Rialto, Behaviour.

    To finish, it deals with additional tools in order to develop and test JavaScript applications.

    A project has been created for this book and can be reached at the following url: http://jsweb2.sourceforge.net/.

    You can have more details on the book on the website of Eyrolles:
    summary, contents and sample chapters. You can reach the page of the book and download the sample chapters at the following url:
    http://www.eyrolles.com/Accueil/Livre/9782212117103/

    You can buy online this book on the following sites:

    Friday, June 30, 2006

    Spring at ECOOP 2006 in Nantes

    Next week, Rob Harrop and Adryan Colyer will make a presentation of Spring AOP during ECOOP 2006 in Nantes:

    "This tutorial provides an introduction to aspect-oriented programming using the Spring framework and AspectJ. Attendees will understand the principles behind AOP, and where it fits in enterprise application development. We demonstrate how to write aspects using the Spring framework, exploiting the AspectJ pointcut language. The @AspectJ (annotation based) style of aspect declaration supported by AspectJ 5 will be explained, including support for using such aspects with the Spring AOP framework. Finally we look at the AspectJ language itself, how it goes beyond the capabilities of Spring AOP, and how to get started with some quick wins on your own projects."

    For more details, see the page decribing this event: http://www.emn.fr/x-info/ecoop2006/Tid7.html

    Friday, June 30, 2006

    Jencks namespace

    Jencks is a project hosted on the codehaus site which allows to embed the transaction and connection managers of Geronimo in every applications.

    In order to simply the configuration of the two different managers, we have developped a dedicated namespace handler for Spring called Jencks. It allows applications to use two tags, transactionManager and connectionManager, which will be described in the following sections.

    The XML grammar of these tags is described in the spring-jencks.xsd file. The content of this file is the following:

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <xsd:schema xmlns="http://www.springframework.org/schema/jencks" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans" targetNamespace="http://www.springframework.org/schema/jencks" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xsd:import namespace="http://www.springframework.org/schema/beans"/>
    <xsd:element name="transactionManager"> <xsd:complexType> <xsd:sequence> <xsd:element name="transactionLog" type="transactionLogType" minOccurs="0" maxOccurs="1" /> </xsd:sequence> <xsd:attribute name="id" type="xsd:ID" /> <xsd:attribute name="userTransactionId" type="xsd:string" /> <xsd:attribute name="transactionContextManagerId" type="xsd:string" /> <xsd:attribute name="connectionTrackerId" type="xsd:string" /> <xsd:attribute name="defaultTransactionTimeoutSeconds" type="xsd:string" /> </xsd:complexType> </xsd:element>
    <xsd:element name="connectionManager"> <xsd:complexType> <xsd:sequence> <xsd:element name="transactionSupport" type="transactionSupportType" minOccurs="0" maxOccurs="1" /> <xsd:element name="poolingSupport" type="poolingSupportType" minOccurs="0" maxOccurs="1" /> </xsd:sequence> <xsd:attribute name="id" type="xsd:ID" /> <xsd:attribute name="transactionContextManager-ref" type="xsd:string" /> <xsd:attribute name="connectionTracker-ref" type="xsd:string" /> </xsd:complexType> </xsd:element>
    <xsd:complexType name="transactionLogType"> <xsd:sequence> <xsd:element ref="beans:bean" /> </xsd:sequence> </xsd:complexType>
    <xsd:complexType name="transactionSupportType"> <xsd:attribute name="useTransactionCaching" type="xsd:boolean" default="true" /> <xsd:attribute name="useThreadCaching" type="xsd:boolean" default="false" /> </xsd:complexType>
    <xsd:complexType name="poolingSupportType"> <xsd:attribute name="maxSize" type="xsd:int" default="2" /> <xsd:attribute name="minSize" type="xsd:int" default="1" /> <xsd:attribute name="blockingTimeoutMilliseconds" type="xsd:int" default="60" /> <xsd:attribute name="idleTimeoutMinutes" type="xsd:int" default="60" /> <xsd:attribute name="matchOne" type="xsd:boolean" default="true" /> <xsd:attribute name="matchAll" type="xsd:boolean" default="true" /> <xsd:attribute name="selectOneAssumeMatch" type="xsd:boolean" default="true" /> </xsd:complexType> </xsd:schema>

    Note that this namespace need the version 2.0 M4 of Spring.

    Installation

    In order to use this namespace handler in Spring, we need to add two files in the META-INF directory of your project.

    Firstly, the spring.handlers file specifies the name of implementation of NamespaceHandler. The follwing code describes the content of this file:

    http\://www.springframework.org/schema/jencks=org.springframework.jca.config.JencksNamespaceHandler
    

    Secondly, the spring.schemas file specifies the location of the xsd file in the classpath. The follwing code describes the content of this file:

    http\://www.springframework.org/schema/jencks=org/springframework/jca/config/spring-jencks.xsd
    

    Configuration of the transaction manager

    The tag transactionManager is used to configuration the JTA transaction manager of Geronimo. It internally creates four beans:

    • Transaction manager (identified by the value of the id attribute)
    • Transaction context manager (identified by the value of the transactionContextManagerId attribute)
    • User transaction (identified by the value of the userTransactionId attribute)
    • Connection tracker (identified by the value of the connectionTrackerId attribute)

    The following code is an example of use of this tag in a application context of Spring:

    <jencks:transactionManager id="transactionManager"
                   userTransactionId="userTransaction"
                   transactionContextManagerId="transactionContextManager"
                   connectionTrackerId="connectionTracker"
                   defaultTransactionTimeoutSeconds="600">
    <jencks:transactionLog> <bean class="org.apache.geronimo.transaction.log.UnrecoverableLog"/> </jencks:transactionLog>
    </jencks:transactionManager>

    Configuration of the connection manager

    The tag connectionManager is used to configuration the JCA connection manager of Geronimo. It can be used in order to configure a connector for outbound communications. It internally creates one bean:

    • Connection manager (identified by the value of the id attribute)

    This tag is based on entites configured by the tag described in the previous section:

    • Transaction context manager (referenced by the value of the transactionContextManager-ref attribute)
    • Connection tracker (referenced by the value of the connectionTracker-ref attribute)

    The following code is an example of use of this tag in a application context of Spring:

    <jencks:connectionManager id="connectionManager"
              transactionContextManager-ref="transactionContextManager"
              connectionTracker-ref="connectionTracker">
    <jencks:transactionSupport useTransactionCaching="true" useThreadCaching="false"/>
    <jencks:poolingSupport maxSize="2" minSize="2" blockingTimeoutMilliseconds="60" idleTimeoutMinutes="60" matchOne="true" matchAll="true" selectOneAssumeMatch="true"/>
    </jencks:connectionManager>

    Thursday, June 08, 2006

    Book: Spring par la pratique

    I'm pleased to announce the publishing of the book "Spring par la pratique" (Eyrolles).

    I have co-written this book with Julien Dubois and Jean-Philippe Retaillé. Rod Johnson has written a great preface.

    The book is the first book dedicated to the Spring framework written in french. It has been added in the list of books on the website of the framework. See the following urls: http://www.springframework.org/books and http://www.springframework.org/bookreview

    You can have more details on the book on the website of Eyrolles:
    summary, contents and sample chapters. You can reach the page of the book and download the sample chapters at the following url:
    http://www.eyrolles.com/Accueil/Livre/9782212117103/

    You can buy online this book on the following sites:

    Friday, March 31, 2006

    Use the JMS support of Spring with Joram

    The aim of this entry is to describe the way to use the JMS support of Spring in order to develop Java/J2EE applications based on the JMS provider Joram.

    Firstly, we will describe the way to configure the ConnectionFactory of Joram in a context of Spring. Then, we will show how to handle the destinations with both JNDI and administration API of Joram. Finally, we will see how to use the JmsTemplate class of Spring in order to send and receive JMS messages basing on Joram.

    Configuration of the ConnectionFactory instance

    The first thing to do is to configure the ConnectionFactory of Joram in order to inject it in the JmsTemplate class of Spring. Joram offers several implementations of the JMS interface ConnectionFactory. We will see the configurations of the one based on tcp and an other used for embedded server.

    Firstly, if you need to access a Joram server with tcp, you must use the TcpConnectionFactory class. This class can be configured as a Bean as following:

    <bean id="connectionFactory"
         class="org.objectweb.joram.client.jms.tcp.TcpConnectionFactory">
        <constructor-arg index="0" value="tcp://localhost/"/>
        <constructor-arg index="1" value="16010"/>
    </bean>
    

    In the case of the class LocalConnectionFactory, you need to use a static factory method in order to instanciate a ConnectionFactory of this type.

    ConnectionFactory connectionFactory=LocalConnectionFactory.create("root","root");
    

    For this class, you can choose to use the support of factory method of Spring or develop a custom FactoryBean as following:

    public class LocalConnectionFactoryBean
                      implements FactoryBean,InitializingBean {
        private ConnectionFactory connectionFactory;
    public Object getObject() throws Exception { return connectionFactory; }
    public Class getObjectType() { return ConnectionFactory.class; }
    public boolean isSingleton() { return true; }
    public void afterPropertiesSet() throws Exception { this.connectionFactory=LocalConnectionFactory.create(); } }

    This class will be configured in Spring as following:

    <bean id="connectionFactory"
             class="test.joram.LocalConnectionFactoryBean"/>
    

    Note that you can too choose to use the JndiObjectFactoryBean in order to get an instance of a ConnectionFactory from JNDI. The following code shows how to configure this strategy:

    <bean id="connectionFactory" class="...JndiObjectFactoryBean">
        <property name="jndiName" value="cnf"/>
    </bean>
    

    Working with destintations

    After having configured your JMS ConnectionFactory for Joram, the strategy to resolve the destinations must be configured. As a matter of fact, the JmsTemplate of Spring can be used both with a parameter 'destination' of type Destionation or a parameter 'destinationName' of type String.

    In the first case, the application is entirely responsible to get the instance of the destination. You can use both JNDI or administration API of Joram. Here is an example of the latter:

    (...)
    JmsTemplate template=createTemplate();
    List destinations=AdminModule.getDestinations(); Destination destination=null; for(Iterator i=destinations.iterator();i.hasNext();) { Destination tmpDestination=(Destination)i.next(); if( !isQueue(destination) ) { continue; }
    if( destinationName.equals(destination.getAdminName()) ) { destination=tmpDestination; } }
    template.send(destination,new MessageCreator() { public Message createMessage(Session session) throws JMSException { (...) return (...); } });

    In the second case, the JMS support of Spring delegates the task to get the destination instance basing on the name of destination to an instance of the interface DestinationResolver. There are two implementations provides by the support: DynamicDestinationResolver (based on the method createQueue and createTopic of JMS API) and JndiDestionationResolver (based on Jndi).

    By defaut, the template uses the first one, but you can provide your own one with the method setDestinationResolver of this class.

    Here is a custom one for Joram named JoramDestinationResolver which looks for the destination thanks to the administration API of the provider. If it doesn't exist, the class uses the same API in order to create it.

    public class JoramDestinationResolver
                         implements DestinationResolver,InitializingBean {
        private static final Object JORAM_QUEUE_TYPE = "queue";
        private static final Object JORAM_TOPIC_TYPE = "topic";
    private JoramAdmin admin; private String hostName; private int port; private String userName; private String password;
    public Destination resolveDestinationName( Session session,String destinationName, boolean pubSubDomain) throws JMSException { List destinations = doGetDestinations(); for(Iterator i=destinations.iterator();i.hasNext();) { Destination destination=(Destination)i.next(); if( !isPubSubDomain(destination,pubSubDomain) ) { continue; }
    if( destinationName.equals(destination.getAdminName()) ) { return destination; } }
    return doCreateDestination(destinationName,pubSubDomain); }
    private Destination doCreateDestination( String destinationName, boolean pubSubDomain) { try { Destination destination=null; if( !pubSubDomain ) { destination=(Destination)admin.createQueue(destinationName); } else { destination=(Destination)admin.createTopic(destinationName); } destination.setFreeReading(); destination.setFreeWriting(); return destination; } catch(AdminException ex) { throw new JoramAdminException( "Unable to create the destination"+ " with the name "+destinationName,ex); } catch (ConnectException ex) { throw new JoramAdminException( "Unable to create the destination with"+ " the name "+destinationName,ex); } }
    private List doGetDestinations() { try { List destinations=AdminModule.getDestinations(); return destinations; } catch(Exception ex) { throw new JoramAdminException("Unable to get the"+ " list of destinations",ex); } }
    private boolean isPubSubDomain( Destination destination, boolean pubSubDomain) { if( !pubSubDomain && JORAM_QUEUE_TYPE.equals(destination.getType()) ) { return true; }
    if( pubSubDomain && JORAM_TOPIC_TYPE.equals(destination.getType()) ) { return true; }
    return false; }
    public void afterPropertiesSet() throws Exception { if( hostName==null || port==0 ) { throw new IllegalArgumentException( "Both hostName and port are required"); }
    if( userName==null || password==null ) { throw new IllegalArgumentException( "Both userName and password are required"); }
    admin=new JoramAdmin(hostName,port,userName,password,60); }
    public String getHostName() { return hostName; }
    public void setHostName(String hostName) { this.hostName = hostName; }
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
    public int getPort() { return port; }
    public void setPort(int port) { this.port = port; }
    public String getUserName() { return userName; }
    public void setUserName(String userName) { this.userName = userName; } }

    Sending JMS messages using the JoramDestinationResolver class

    This DestinationResolver implementation can be used as following in order to send JMS messages with the JmsTemplate class.

    (...)
    JmsTemplate template=createTemplate();
    JoramDestinationResolver resolver=new JoramDestinationResolver();
    resolver.setHostName("localhost");
    resolver.setPort(16010);
    resolver.setUserName("root");
    resolver.setPassword("root");
    resolver.afterPropertiesSet();
    template.setDestinationResolver(resolver);
    template.send(destinationName,new MessageCreator() { public Message createMessage(Session session) throws JMSException { (...) return (...); } });

    Receiving JMS messages using the JoramDestinationResolver

    Since its version 2.0, Spring offers support for JMS asynchronous communications with the classes SimpleMessageListenerContainer and ServerSessionMessageListenerContainer which must be configured with an instance of the class MessageListener of the JMS specification.

    These two classes support the mechanism based on the DestinationResolver interface in order to get an instance of a destination using its name.

    Here is an example based on a JMS MessageListener:

    <bean id="myJmsListener" class="test.joram.MyJmsListener"/>
    <bean id="destinationResolver" class="joram.JoramDestinationResolver"> <property name="hostName" value="localhost"/> <property name="port" value="16010"/> <property name="userName" value="root"/> <property name="password" value="root"/> <bean>
    <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="connectionFactory" ref="connectionFactory"/> <property name="destinationResolver" ref="destinationResolver"/> <property name="destinationName" value="test.queue"/> <property name="messageListener" ref="myJmsListener"/> </bean>

    Wednesday, November 23, 2005

    Jencks in action

    The aim of this article is to describe the use of Jencks (http://jencks.org). It is based on the version 1.1.1 of the project.

    This project allows application to use the transaction and connector modules with the JCA support of Spring in order to use JCA in a managed mode outside a J2EE application server. It allows to develop more lightweight applications and to embed XA features into every applications even if they are not deployed in an application server.

    JCA support of Spring

    The JCA support of Spring provides a dedicated FactoryBean implementation, LocalConnectionFactoryBean, to configure a JCA connector in a non managed mode. You can too use it to configure a connector in a managed mode if you specify an implementation of the JCA ConnectionManager interface in addition to the ManagedConnectionFactort as described in the following code.

    <bean id="connectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean">
      <property name="managedConnectionFactory"><ref local="managedConnectionFactory"/></property>
      <property name="connectionManager"><ref local="connectionManager"/></property>
    </bean>
    

    Note that the LocalConnectionFactoryBean class can be used to expose different interfaces like the JMS ConnectionFactory, the JDBC DataSource, the Hibernate SessionFactory, of course the JCA ConnectionFactory...

    When using this feature, you are now able to add your resources in the context of global transactions and use them with JTA.

    Jencks

    Jencks is very close to the Geronimo and Spring projects. As a matter of fact, it provides dedicated FactoryBean to configure resources of the connector and transaction modules of Geronimo.

    The first step to use Jencks is to configure the transaction module as following.

    <bean id="connectionTracker"
          class="org.apache.geronimo.connector.outbound.connectiontracking.ConnectionTrackingCoordinator"/>
    <bean id="transactionManagerImpl" class="org.jencks.factory.TransactionManagerFactoryBean"> <property name="defaultTransactionTimeoutSeconds" value="600"/> <property name="transactionLog"> <bean class="org.apache.geronimo.transaction.log.UnrecoverableLog"/> </property> </bean>
    <bean id="transactionContextManager" class="org.jencks.factory.TransactionContextManagerFactoryBean"> <property name="transactionManager" ref="transactionManagerImpl"/> </bean>
    <bean id="userTransaction" class="org.jencks.factory.UserTransactionFactoryBean"> <property name="transactionContextManager" ref="transactionContextManager"/> <property name="connectionTrackingCoordinator" ref="connectionTracker"/> </bean>

    The connector module will use the entities in order to be able to use global transactions.

    The next step is to configure the ConnectionManager implementation of Geronimo. It provides a pooling mechanism and a contract with the transaction manager. So you must configure a ConnectionManager for each factories (DataSource, SessionFactory, ConnectionManager...).

    The configuration of the XA JMS ConnectionFactory of ActiveMQ is described in the following code. It is based on the ActiveMQ JCA connector. Firstly, you must configure the ConnectionManager and then the connector using it. Note that the configuration of ConnectionManager is similar for every connector.

    <bean id="transactionSupport"
          class="org.jencks.factory.XATransactionFactoryBean">
      <property name="useTransactionCaching" value="true"/>
      <property name="useThreadCaching" value="false"/>
      </property>
    </bean>
    <bean id="poolingSupport" class="org.jencks.factory.SinglePoolFactoryBean"> <property name="maxSize" value="2"/> <property name="minSize" value="1"/> <property name="blockingTimeoutMilliseconds" value="60"/> <property name="idleTimeoutMinutes" value="60"/> <property name="matchOne" value="true"/> <property name="matchAll" value="true"/> <property name="selectOneAssumeMatch" value="true"/> </bean>
    <bean id="jmsConnectionManager" class="org.jencks.factory.ConnectionManagerFactoryBean"> <property name="transactionSupport" ref="transactionSupport"/> <property name="poolingSupport" ref="poolingSupport"/> <property name="transactionContextManager" ref="transactionContextManager"/> <property name="connectionTracker" ref="connectionTracker"/> </bean>

    Then you need to configure the connector basing the ConnectionManager previously configured. Here is a sample with the connector of ActiveMQ. In this case, you can inject the JMS ConnectionFactory configured which is internally XA compliant. So it can participate in a 2PC transaction.

    <bean id="jmsResourceAdapter" class="org.activemq.ra.ActiveMQResourceAdapter">
      <property name="serverUrl" value="tcp://localhost:61616"/>
      </bean>
    <bean id="jmsManagedConnectionFactory" class="org.activemq.ra.ActiveMQManagedConnectionFactory"> <property name="resourceAdapter" ref="jmsResourceAdapter"/> </bean>
    <bean id="jmsConnectionFactory" class="org.springframework.jca.support.LocalConnectionFactoryBean"> <property name="managedConnectionFactory" ref="jmsManagedConnectionFactory"/> <property name="connectionManager" ref="jmsConnectionManager"/> </bean>

    Transaction demarcation with Spring

    With the use of Jencks, you can manage transactions in your application normally with the classic support of Spring. In this case, the implementation of the PlatformTransactionManager interface to use is JtaTransactionManager.

    For more information, see the chapter Transaction management in the reference documentation of Spring. The following code shows how to configure the JtaTransactionManager with the previous configured beans.

    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
      <property name="userTransaction" ref="userTransaction"/>
      <property name="transactionManager" ref="transactionManagerImpl"/>
    </bean>
    

    In this howto, we have described the way to use Jencks, ActiveMQ and Spring to make global transactions with JCA and Geronimo outside the application server. The article is focused on the outbound communication of JCA. As the ActiveMQ connector is 1.5 compliant, you can use Jencks with inbound communication. I will describe this feature in a next howto.

    Friday, November 04, 2005

    JMX notifications with Spring (2)

    The second part of the thread describe the end of the support of JMX notifications in Spring. Like the previous one, it describes the patch I have written to address the issue SPR-680 in JIRA.

    See the second zip file (SpringJMX_Notification_v1.1.zip) on the issue for the implementation of this patch.

    Support of filters

    When a JMX notification listener is added to an MBean, you can pass a filter to select notifications the listener will accept. In our case, we use the class NotificationFilterSupport which implements NotificationFilter and allow configure the allow and deny of notifications types.

    public class NotificationListenerSupport {
      ...
      public synchronized boolean isNotificationEnabled(
                           Notification notification) {...}
      public synchronized void enableType(String type)
                   throws IllegalArgumentException {...}
      public synchronized void disableType(String type) {...}
      public synchronized void disableAllTypes() {...}
      public synchronized Vector getEnabledTypes() {...}
      ...
    }
    

    To associate filters with listeners on the MBeanExporter class, you need to set the notificationFilters property which tokens are delimited by the character ','. If the element starts with the character '+', the nofication type is allowed and if it starts with '-', the type is denied. The following listing shows an example of use.

    <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
      <property name="beans">
        ...
      </property>
      <property name="notificationListeners">
        <list>
          <ref local="listener"/>
        </list>
      </property>
      <property name="notificationFilters">
        <value>DENY_ALL_TYPES,+test</value>
      </property>
    </bean>
    

    Note: This feature is supported on the NotifierFactoryBean class too.

    Support of handback

    Handback is an object specified on the call of addNotificationListener which is then given to the listener when a notification is triggered. The patch supports now this feature with the handback property of the MBeanExporter class. The following listing shows an example of use.

    <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
      <property name="beans">
        ...
      </property>
      <property name="notificationListeners">
        <list>
          <ref local="listener"/>
        </list>
      </property>
      <property name="notificationFilters">
        <value>DENY_ALL_TYPES,+test</value>
      </property>
      <property name="handback" value="test handback"/>
    </bean>
    

    Note: This feature is supported on the NotifierFactoryBean class too.

    Friday, November 04, 2005

    JMX notifications with Spring

    The Spring framework offers a great support of JMX. The aims of this support are:

    • automatically convert simple beans into MBeans
    • automatically register simple beans and MBeans declaratively
    • configure an embedded JMX server
    • configure JMX connectors to access to the components of the agent layer

    At this time, the support doesn't include JMX notifications but it's planned for the version 1.3RC2. See the issue SPR-680 in JIRA: http://opensource2.atlassian.com/projects/spring/browse/SPR-680

    I have developped some code to implement this issue. Its aims are:

    • provide a way to add/remove JMX listeners on registred MBeans based on their object names
    • provide a way to add/remove JMX listeners on simple beans and MBean exported on the JMX server with Spring facilities.
    • offer an abstraction to allow bean or MBean exported with to send notifications

    Add/remove JMX listeners on registered MBeans

    The aim of this part is to add/remove listeners on MBean not registered with Spring facilities. The common example is to listen events triggered by the MBean server delegate. This entity sends notifications on register/unregister MBean events. The following listing shows how to configure it.

    <bean id="delegateListeners" class="org.springframework.jmx.export.notifier.NotifierFactoryBean">
      <property name="server"><ref local="mbeanServer"/></property>
      <property name="objectName">
        <value>
          JMImplementation:type=MBeanServerDelegate
        </value>
      </property>
      <property name="notificationListeners">
        <ref local="listener"/>
      </property>
    </bean>
    <bean id="listener" class="TestNotificationListener"/>

    The class testNotificationListener is a classic JMX notification listener as shown in the following listing:

    public class TestNotificationListener
                     implements NotificationListener {
      public void handleNotification(
                     Notification notification, Object handback) {
        System.out.println("Notification received.");
        System.out.println(" -> "+notification);
      }
    }
    

    The listener receives the following notifications for example:

    Notification received.
     -> javax.management.MBeanServerNotification
              [source=JMImplementation:type=MBeanServerDelegate]
                           [type=JMX.mbean.registered][message=]
    Notification received.
     -> javax.management.MBeanServerNotification
              [source=JMImplementation:type=MBeanServerDelegate]
              [type=JMX.mbean.unregistered][message=]
    

    Add/remove JMX listeners on MBeans registered with Spring

    The support distinguishes two possibilities according to the kind of instance to export.

    First the bean ot export is a simple bean not tied with JMX. In this case, the JMX support of Spring uses model MBean to convert the bean into an MBean according to different strategies to know attributes and methods to expose. The RequiredModelMBean already implements the NotificationBroadcaster, so there is nothing to do, but the listeners must be added not on the bean but on the created model MBean.

    Secondly the bean is a MBean (so tied with JMX). In this case, the support looks if the MBean implements the NotificationBroadcaster. This JMX interface allows MBean to register and unregister notification listeners.

    If not, AOP is used to add this interface to the bean with the method introduction feature. The implementation of this interface is the GenericBroadcaster class based on the NotificationBroadcasterSupport of JMX.

    The following listing shows an example of use in this case.

    <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
      <property name="beans">
        <map>
          <entry key="bean:name=testBean1"
                    value-ref="testBean"/>
          <entry key="bean:name=testBean2"
                    value-ref="testSimpleBean"/>
        </map>
      </property>
      <property name="notificationListeners">
        <ref local="listener"/>
      </property>
      <property name="server" ref="mbeanServer"/>
    </bean>
    <bean id="listener" class="TestNotificationListener"/>

    Send notifications from simple beans and MBeans registered with Spring

    To send a notification, the simple bean or the MBean needs an abstraction. This abstraction must just have a method to send a notification. I define the Notifier interface as following:

    public interface Notifier {
      void notify(NotificationCreator creator,Object handback);
    }
    

    One of the challenge is to give an instance of this interface. The simple bean or MBean must tell the JMX support that it can accept this by implementing the NotifierAware interface. It works like the other *Aware interfaces (ApplicationContextAware, BeanFactoryAware) in Spring. If the support detects this interface, it will call the method setNotifier on it.

    public interface NotifierAware {
      void setNotifier(Notifier notifier);
    }
    

    The following listing shows an example to send a notification.

    public class MyBean
      public void test() {
        notifier.notify(new NotificationCreator() {
          public Notification createNotification() {
            return new Notification("test",this,0);
          }
        },null);
      }