Friday, July 25, 2008

Spring Web services and Axis2

As you know Axis2 is a Web service framework which has support many things. It has support for scripting languages , it has support for data services and it has support for EJB , Corba and etc. In addition that since a long time it has support for Spring as well. With that you can deploy Spring bean as Web services in Axis2. Yes I agree it is yet another way of getting the thing done. I also realized that is not enough for spring developers. They need everything works on spring.

To solve that in WSO2 we came up with a solution where we have integrated Axis2 into Spring. When doing this we have convert all the axis2 configurations files into bean descriptors , for example we came up with a set of beans for axis2.xml. With this we have integrated Axis2 smoothly into Spring. After thing anyone can easily expose a bean as a Web service. And get the power of all the other WS* support , such as security , reliability etc. , above all you can get the power of Axis2 while you are in spring container.

With this approach you can make a bean into a Web service just using following line of codes

<bean id="services" class="org.wso2.spring.ws.WebServices">
<property name="services">
<list>
<bean id="helloService" class="org.wso2.spring.ws.SpringWebService">
<property name="serviceBean" ref="helloworld"></property>
<property name="serviceName" value="helloWorldService"></property>
</bean>
</list>
</property>
</bean>

You can read more about Spring support from the following links

WSO2 Web Services Framework for Spring

Hello World with WSO2 WSF/Spring

by Deepal Jayasinghe

Tuesday, July 22, 2008

Unit test with Spring Dynamic Modules

Follow our story about developing services by using Spring Dynamic Modules. We are developing our application and we have already migrated our application to support osgi. During migration, we have some problems with our test classes, we wanted to run our unit test in osgi environment (so we called integration test - integration test in osgi environment should be the better choice because we can check the class resolving among bundles besides of making sure all business rules are run properly). We already have a lot of unit tests written by JUnit 4 (which are based on Unitils and we already developed a bunch of test module such as Servlet Container, Ldap etc) and unfortunately they can not run in osgi environment. This post is our experience while we develop our integration test base on Spring DM testing framework, actually the cost of migration from our unit test is not much, most of time for researching how to do and simply replaces the revelant things of Unit 4 to Unit 3. Spring DM testing framework supports integration test but for JUnit 3 only now. Here is the general scenerio of Spring DM supports to run integration testing (quoted from Spring DM reference document)

  • Start the OSGi framework (Equinox, Knopflerfish, Felix)

  • install and start any specified bundles required for the test

  • package the test case itself into a on the fly bundle, generate the manifest (if none is provided) and install it in the OSGi framework

  • execute the test case inside the OSGi framework

  • shut down the framework

  • passes the test results back to the originating test case instance that is running outside of OSGi

Setting the integration test environment

Make sure that the following necessary files belong your class-path:

  • spring-osgi-core-1.1.0
  • spring-osgi-extender-1.1.0
  • spring-osgi-io-1.1.0
  • spring-osgi-test-1.1.0

Creating the first Osgi integration test

All integration test class must inherit the org.springframework.osgi.test.AbstractConfigurableBundleCreatorTest. The first step is creating our base class for all osgi integration testing:

/**
 * The base class of integration testing of Engroup. All integration testing
 * classes must be derived from this class
 *
 */
public class AbstractEngroupOsgiTest extends
  AbstractConfigurableBundleCreatorTests {
   ...
}

Configuring boot bundles of Spring DM

By default, Spring DM testing frameworks will load some default bundles before loading specific bundles for your test. You can see the default bundles loaded by Spring DM testing framework at org.springframework.osgi.test.internal.boot-bundles of spring-test project. In some cases, you need to replace the boot bundles of Spring DM testing framework by your bundles. The typical scenario that you need to do that is case you already have some bundles, in these bundles you add some extra osgi meta data (such as DynamicImport-Package field to allow the bundle can dynamic load class at runtime). Having the same package with the same version is prohibited. In addition, we are doing integration test, so make the test environment is similar with real environment is a must. Spring DM allows you can inject the new configuration of boot bundles by simply override the method getTestingFrameworkBundlesConfiguration of class AbstractConfigurableBundleCreatorTest.

Example 1: Inject the new configuration of boot bundles for Spring DM testing

private static final String TEST_FRRAMEWORK_BUNDLES_CONF_FILE = "/META-INF/boot-bundles.properties";
...
@Override
protected Resource getTestingFrameworkBundlesConfiguration() {
  return new InputStreamResource(AbstractEngroupOsgiTest.class
    .getResourceAsStream(TEST_FRRAMEWORK_BUNDLES_CONF_FILE));
}

Customizing the bundle content

Due to your test class is bundled in on-the-fly bundle. You can customize the manifest file of this bundle. In some cases, it is the must for complex case while the test class use the class of other bundles run during test executing. To do this, you simply override the method getManifestLocation (note that you can change the content of manifest file programatically by override the method getManifest, however we prefer to use the manifest file)

Example 2: Customizing the test manifest file

@Override
protected String getManifestLocation() {
    return "classpath:META-INF/MANIFEST.MF";
}

Example 3: Customized manifest file

Manifest-Version: 1.0
Embed-Directory: lib
Implementation-Title: Engroup Osgi Integration Test
Spring-Version: 2.5.5
Bundle-Activator: org.springframework.osgi.test.JUnitTestActivator
Implementation-Version: 2.5.5
Tool: Bnd-0.0.160
Bundle-Name: engroup-integration-test
Created-By: 1.6.0 (Sun Microsystems Inc.)
Bundle-Version: 0.0.1
Bnd-LastModified: 1207763595575
Bundle-ManifestVersion: 2
Import-Package:
 com.engroup.module.common.domain,
 com.engroup.module.common.service,
 …
 com.mysql.jdbc,
 javax.jcr,
 javax.naming,
 javax.naming.directory,
 javax.naming.ldap,
 javax.sql,
 junit.framework,
 org.dbunit,
 org.dbunit.database,
 org.dbunit.dataset,
 org.dbunit.dataset.xml,
 org.dbunit.operation,
 org.osgi.framework,
 org.springframework.context,
 …
Bundle-ClassPath: .,
 {src/test/resources}
Bundle-SymbolicName: engroup.server.engroup-integration-test
Include-Resource: {src\test\resources}

Some tips of writing Osgi Integration Test

  1. Set the default wait timer of creating spring context:
    Waiting time is set to wait until all dependencies are resolved before running test execution. Base on practice the waiting time is varied but limit under 20s (in our project). However, to support debugging while running integration test, the longer value should be set to prevent Spring DM interupt the test while developers are debugging the test program.Example 4: Set the wait time override the default value of Spring DM
        @Override
        protected long getDefaultWaitTime() {
            return 3000;
        }
  2. Inject spring beans in test class:
    We use Spring DM with the purpose that Spring beans could be exposed as the osgi services and used in other bundles. Of course, we would like to test spring beans in integration testing. To use spring, make sure the integration test class load the spring context files firstExample 5: Load the spring context files
         @Override
         protected String[] getConfigLocations() {
             return new String[] {
                 "classpath:META-INF/spring/hr-context-osgi-test.xml",
                 "classpath:META-INF/spring/common-context-osgi-test.xml",
                 "META-INF/spring/db-context-osgi-test.xml" };
         }

    Note: All spring context files should only declare only spring beans are exposed by other bundles and remember to import the necessary packages in your manifest file

    Example 6: Spring context file declares the spring bean service exported by other bundles and they serve for testing purpose

    <beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:osgi="http://www.springframework.org/schema/osgi"
     xsi:schemaLocation=
      "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd">
     <osgi:reference id="companyService"
      interface="com.engroup.module.hr.service.CompanyService" />
    
     <osgi:reference id="divisionService"
      interface="com.engroup.module.hr.service.DivisionService" />
    ...

    Now, it is ready to inject our spring beans to test class by injecting the spring bean to protected objects of test class

    Example 7: Inject the spring bean to test class protected fields

       protected CompanyService companyService;
    
       public AbstractEngroupOsgiTest() {
           setPopulateProtectedVariables(true);
       }

    Now, you can use companyService spring bean is exposed from other bundles in your test method.

by haiphucnguyen

Sunday, July 13, 2008

Seam, Spring and jBPM integration HowTo

This HowTo describes a way to integrate Seam, Spring and jBPM in order to use the same Hibernate SessionFactory in both Spring and jBPM (and of course, Seam).

At first, make sure you use the latest version 2.1.0 of Seam since you could get trouble with 2.0.1 and SpringTransactions.

The relevant parts of the configuration are:

- in your Spring bean config, define your Hibernate sessionFactory as usual and set the following properties in special

<bean id=“hibernateSessionFactory”
class=“…”>

<!– The hibernate properties  –>
<property name=“hibernateProperties”>
<props>

<prop key=“hibernate.hbm2ddl.auto”>update</prop>
<!– set to create-drop to NOT maintain state between two executions of the app –>

<prop
key=“hibernate.transaction.flush_before_completion”>
true
</prop>
<prop key=“hibernate.connection.release_mode”>
after_transaction
</prop>

</props>
</property>

<!– this property must be set to false so we can use independent sessions –>
<property name=“useTransactionAwareDataSource”>
<value>false</value>
</property>

<property name=“mappingResources”>
<list>

<!– here you have to list all the *hbm.xml files for jBPM –>
<!– see the default hibernate.cfg.xml file from jBPM –>

</bean>

- second, for the Seam Spring integration we need two beans

<bean id=“sessionFactory”
class=“org.jboss.seam.ioc.spring.SeamManagedSessionFactoryBean”>
<property name=“sessionName” value=“hibernateSession” />
</bean>
<bean id=“localTransactionManager”
class=“org.springframework.orm.hibernate3.HibernateTransactionManager”>
<property name=“sessionFactory” ref=“hibernateSessionFactory” />
</bean>

That’s it for Spring configuration.

Now in components.xml, we need

<!– use the power of Spring transactions –>
<spring:spring-transaction platform-transaction-manager-name=“localTransactionManager”/>

<persistence:managed-hibernate-session name=“hibernateSession” auto-create=“true”
session-factory=“#{hibernateSessionFactory}”/>

<component class=“org.jboss.seam.bpm.Jbpm”>
<property name=“processDefinitions”>processdefinition.jpdl.xml</property>
</component>

In order to use the hibernateSession in jBPM, I subclassed the DbPersistenceService from jBPM. You need two classes:

package your.namespace.jbpm.integration;

import org.hibernate.Session;
import org.hibernate.SessionFactory;

import org.jboss.seam.Component;
import org.jboss.seam.contexts.Contexts;

import org.jbpm.svc.Service;

/**
* @author Frank Bitzer
*
*
*
*/

public class DbPersistenceServiceFactory extends
org.jbpm.persistence.db.DbPersistenceServiceFactory {

private static final long serialVersionUID = 997L;
SessionFactory sessionFactory;

/**
* {@inheritDoc}
*/
public Service openService() {

//create instance of own service implementation
return new your.namespace.jbpm.integration.DbPersistenceService(this);
}

/**
* Retrieve Hibernate sessionFactory
*/
@Override
public synchronized SessionFactory getSessionFactory() {

if (sessionFactory==null) {

if(Contexts.isApplicationContextActive()){

//access seam component holding session
Session session = (Session)
Component.getInstance(“hibernateSession”);

//and extract sessionFactory
sessionFactory = session.getSessionFactory();

}

}

return sessionFactory;
}

/**
* Set sessionFactory
*/
@Override
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}

}

package your.namespace.jbpm.integration;

import org.hibernate.Session;
import org.jbpm.JbpmContext;
import org.jbpm.persistence.db.DbPersistenceServiceFactory;
import org.jbpm.svc.Services;
import org.springframework.orm.hibernate3.SessionFactoryUtils;

/**
* @author Frank Bitzer
*
*
*
*/
public class DbPersistenceService extends
org.jbpm.persistence.db.DbPersistenceService {

private static final long serialVersionUID = 996L;

public DbPersistenceService(
DbPersistenceServiceFactory persistenceServiceFactory) {
this(persistenceServiceFactory, getCurrentServices());
}

static Services getCurrentServices() {
Services services = null;
JbpmContext currentJbpmContext = JbpmContext.getCurrentJbpmContext();
if (currentJbpmContext != null) {
services = currentJbpmContext.getServices();
}
return services;
}

DbPersistenceService(DbPersistenceServiceFactory persistenceServiceFactory,
Services services) {

super(persistenceServiceFactory);

this.persistenceServiceFactory = persistenceServiceFactory;
this.isTransactionEnabled = persistenceServiceFactory
.isTransactionEnabled();
this.isCurrentSessionEnabled = persistenceServiceFactory
.isCurrentSessionEnabled();
this.services = services;

}
/**
* Use Hibernate sessionFactory to retrieve a Session instance.
*/
public Session getSession() {

if ((session == null) && (getSessionFactory() != null)) {

session = getSessionFactory().openSession();

mustSessionBeClosed = true;
mustSessionBeFlushed = true;
mustConnectionBeClosed = false;

isTransactionEnabled = !SessionFactoryUtils.isSessionTransactional(
session, getSessionFactory());

if (isTransactionEnabled) {

beginTransaction();
}

}
return session;
}

}

To finish work, simply use the brand-new DbPersistenceService in jbpm.cfg.xml like


<jbpm-context>
<service name=“persistence”>
<factory>
<bean class=“your.namespace.jbpm.integration.DbPersistenceServiceFactory”>
<field name=“isTransactionEnabled”>
<false/>
</field>
</bean>
</factory>
</service>


</jbpm-context>

Also make sure your Spring WebApplicationContext is initialized before the startup of Seam. This can be achieved by placing the org.jboss.seam.servlet.SeamListener behind the listener for Spring in your web.xml.

That’s it! Now everything should work fine.

Note that I also contributed this HowTo to the official Seam Knowledge Base. You can find it here.