Tag Archive for 'jsr220'

Implementing JEE with Spring and WebLogic

At JavaOne Interface21 and BEA Systems announced they have jointly developed implementations of key Java EE 5 components on Spring Framework 2.0. They have unveiled an open source project that comprises Spring support for the Java EE 5 Common Annotations (JSR-250), which includes resource injection and EJB 3 (JSR-220) interception. This project is used to implement JEE5 inside the next generation of WebLogic Server, and is also available for use within JSE environments.

package com.cdupuis.ejb3;

import javax.annotation.PostConstruct;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

@Stateless
@Remote(Echo.class)
public class EchoBean implements Echo {

    private static final Log LOG =
        LogFactory.getLog(EchoBean.class);

    private EchoVo echoVo;

    public String echo(String say) {
        return this.echoVo.getEcho() + " " + say;
    }

    @PostConstruct
    public void init() {
        LOG.info("init " + echoVo);
    }

    public void setEchoVo(EchoVo echoVo) {
        LOG.info("setEchoVo called " + echoVo);
        this.echoVo = echoVo;
    }
}

In addition to defining a JavaBean property called echoVo the EJB has a custom init method which is annotated which javax.annotation.PostConstruct. That annotation is defined in JSR-250 and can be used to define certain callback methods at certain lifecycle events.

To actually make Spring aware of that EJB, you need to define a common Spring bean definition which should be called spring-ejb-jar.xml by default. This file needs to be placed in the META-INF directory of your EJB artifact. There are no special beans required in your application context.

For now the id of the Spring Bean should be the name of the EJB that needs to be configured.

<!DOCTYPE beans
    PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
    <bean id="EchoBean">
        <property name="echoVo">
            <bean class="com.cdupuis.ejb3.EchoVo">
                <property name="echo" value="Hello" />
            </bean>
        </property>
    </bean>
</beans>

Now you are ready to deploy the EJB and let Spring handle all the dependency injection and bean lifecycle. It is important to note that the dependency injection happens at first invocation. So make sure that you invoke a business method of your EJB in order to actually see the wiring happening.

Using full power of the Spring AOP

The delivered implementation can do much more then specified within the EBJ 3.0 specification. This is especially interesting in the area of AOP. The EJB 3.0 specification defines little support for method intercepting based on custom annotations. That approach to AOP has been discussed very often recently and is - in my opinion - not something one would use in a real world scenario.

With the integration of Spring 2.0 in the core of WebLogic you can leverage full support for Spring AOP (as well as Spring 2.0’s AspectJ integration) in your application.

The following spring-ejb-jar.xml uses a BeanNameAutoProxyCreator to add a performance interceptor to the EJB defined in the preceding section.

<!DOCTYPE beans
    PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
    <bean
        class="org.sfw…BeanNameAutoProxyCreator">

        <property name="beanNames" value="EchoBean" />
        <property name="interceptorNames"
            value="performanceInterceptor" />

    </bean>

    <bean id="performanceInterceptor"
        class="org.sfw…PerformanceMonitorInterceptor">

        <property name="loggerName" value="com.cdupuis.ejb3" />
    </bean>

    <bean id="EchoBean" />

</beans>

You can even take the AOP magic a little further by using Spring 2.0’s <aop:aspectj-autoproxy /> facility and plug-in your @AspectJ-style Aspects. Here is an example TracingAspect:

package com.cdupuis.ejb3.aspect;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class TracingAspect {

    private static final Log LOG =
        LogFactory.getLog(TracingAspect.class);

    @Before("execution(* *..EchoBean.echo(..))")
    public void before(JoinPoint thisJoinPoint) {
        LOG.info("Before [" + thisJoinPoint.toShortString() + "]");
    }
}

and the corresponding spring-ejb-jar.xml:

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

    <aop:aspectj-autoproxy />

    <bean id="tracingAspect"
        class="com.cdupuis.ejb3.aspect.TracingAspect" />

    <bean id="EchoBean" class="com.cdupuis.ejb3.EchoBean">
        <property name="echoVo">
            <bean class="com.cdupuis.ejb3.EchoVo">
                <property name="echo" value="Hello" />
            </bean>
        </property>
    </bean>

</beans>

Conclusion

The integration of Spring into the core of WebLogic delivers a solid solution to JSR-220 and JSR-250. Furthermore it seems to be possible to leverage other Spring features which do not depend on the EJB specification but add much value to your application; for example transaction demarcation based on Spring’s transaction abstraction layer, integration of ACEGI for handling security on your EJB methods and other AOP and DI features. That can increase significantly the portability of your application and help decoupling it from the underlying EJB technology. You can read more details here UsingJsr220inWebContainer.

Please note that the current implementation is a “Tech Preview” and will be subject to changes on its way to a final product. Furthermore you will not get any support for that from BEA right now.

Using JSR-220/250 with Spring on Tomcat

In my previous post Implementing JEE with Spring 2.0 and BEA WebLogic I described the basic steps to use the Spring-based JSR-220 and 250 implementation within BEA’s WebLogic Tech Preview. In the conclusion of the article I stated that the use of the new framework enriches the portability of an application.

After the public availability of the source code and documentation of Pitchfork project, which is the open source project integrated into WebLogic, I decided to prove my portability statement. Therefore I take my example EJB 3.0 stateless session bean and port that to a Tomcat web container. Currently Tomcat certainly does not know anything about JSR-220 or 250 annotations.

Just to recap, here is the EJB 3.0 SLSB. You can see that I have added an @Interceptors annotation. In my opinion - and I’m not alone with that - the usecase of that annotation and the whole AOP stuff specified with the EJB 3.0 specification in general is definitely way too limited and by far too invasive (defining the pointcut right inside the advised code is not the right approach to attach an advice). Therefore please consider the use of the @Interceptors annotation as an example that I choose to demonstrate the feature set of the Pitchfork Spring add-on.

package com.cdupuis.ejb3;

import javax.annotation.PostConstruct;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;

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

import com.cdupuis.ejb3.aspect.TacingAspectEjb3;

@Stateless
@Remote(Echo.class)
public class EchoBean implements Echo {

    private static final Log LOG =
        LogFactory.getLog(EchoBean.class);

    private EchoVo echoVo;

    @Interceptors( { TacingAspectEjb3.class })
    public String echo(String say) {
        LOG.info("echo called " + say);
        return this.echoVo.getEcho() + " " + say;
    }

    @PostConstruct
    public void init() {
        LOG.info("init " + echoVo);
    }

    public void setEchoVo(EchoVo echoVo) {
        LOG.info("setEchoVo called " + echoVo);
        this.echoVo = echoVo;
    }
}

and the corresponding spring-ejb-jar.xml which is still located in the META-INF directory.

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

    <bean id="EchoBean" class="com.cdupuis.ejb3.EchoBean">
        <property name="echoVo">
            <bean class="com.cdupuis.ejb3.EchoVo">
                <property name="echo" value="Hello" />
            </bean>
        </property>
    </bean>

</beans>

Integrating annotated services in an web application

In order to use the EchoBean outside of BEA’s WebLogic Server, for example in an web application deployed in a Tomcat web container, and still leverage all the fancy dependency injection stuff based on JSR-220 and 250 annotations, one just need to make sure that the required bootstrapping actually happens. That can be accomplished pretty easy with the Bootstrap classes delivered with the Pitchfork framework.

A custom JeeContextLoaderListener and corresponding JeeContextLoader loads every Spring bean definition file named /META-INF/spring-ejb-jar.xml and applies Pitchfork’s JeeBeanFactoryPostProcessor to every loaded BeanFactory. Please not that the JeeContextLoaderListener is not yet part of the Pitchfork or Spring framework release.

The required code is fairly straight forward:

package org.springframework.jee.web.context;

import javax.servlet.ServletContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.sfw.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.context.ContextLoader;

public class JeeContextLoader
        extends ContextLoader {

    private final Log LOG = LogFactory.getLog(ContextLoader.class);

    protected ApplicationContext loadParentContext(
            ServletContext servletContext)
            throws BeansException {

        if (LOG.isInfoEnabled()) {
            LOG.info("Bootstrapping JEE application context");
        }

        ApplicationContext parentContext = new ClassPathXmlApplicationContext(
            new String[] { "classpath*:/META-INF/spring-ejb-jar.xml",
              "classpath:/org/sfw/jee/web/context/spring-jee-bootstrap.xml" });

        return parentContext;
    }
}

The spring-jee-bootstrap.xml contains just one bean definition: The org.springframework.jee.config.JeeBeanFactoryPostProcessor

Here is the required definition of the JeeContextLoaderListener in the web.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

    <listener>
        <listener-class>
            org.sfw.jee.web.context.JeeContextLoaderListener
        </listener-class>
    </listener>

    …

</web-app>

After deploying the web application the beans defined in spring-ejb-jar.xml file(s) are managed by the web application’s root Spring application context and can be used for wiring with other beans defined in servlet application contexts. Certainly all annotations are processed.

To stay with the example: The EchoBean will be advised with JSR-220 interceptor based on the @Interceptors definition, even tough the application is running on a Tomcat instance.

Conclusion

What that example demonstrated is that it is very easy to migrate a EJB 3.0 based application to any other environment without changing any application code. At the end the EJB 3.0 SLSB is certainly not a EJB anymore but a stateless Spring bean, annotated with some useless annotations (@Stateless or @Remote).That is due to the fact that the Pitchfork framework is not bound to BEA’s WebLogic Server and can be used with any other environment. Isn’t that nice … ?