How to call a stateless EJB from a spring rest servlet component

In my recent project I was ask to develop a rest servlet (using jersey) in a spring web project that would call an stateless EJB, where the business logic is.  This project is deployed on glassfish.

After several hours I was able to figure out how to make it work, and my main problem is simply the JNDI name, I was only able to access it using it's global name which you can see on the glassfish console log. It's very important so look at your console.

I would just copy and paste the most important files as they are in my working project. Note that I have 2 projects, that are deploy sub-modules of an ear project. First is a web project and the second is an ejb project.

The Web Project
web.xml
<web-app version="3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemalocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <display-name>XXX - Customer Gateway</display-name>

 <context-param>
  <param-name>locatorFactorySelector</param-name>
  <param-value>classpath:WEB-INF/beanRefContext.xml</param-value>
 </context-param>

 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>

 <servlet>
  <servlet-name>jersey-serlvet</servlet-name>
  <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
  <init-param>
   <param-name>com.sun.jersey.config.property.packages</param-name>
   <param-value>com.XXX.cg</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
 </servlet>

 <servlet-mapping>
  <servlet-name>jersey-serlvet</servlet-name>
  <url-pattern>/api/*</url-pattern>
 </servlet-mapping>
</web-app>
beanRef.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

 <bean id="com.XXX"
  class="org.springframework.context.support.ClassPathXmlApplicationContext">
  <constructor-arg>
   <list>
    <value>applicationContext.xml</value>
   </list>
  </constructor-arg>
 </bean>
</beans>
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:util="http://www.springframework.org/schema/util"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.0.xsd
 http://www.springframework.org/schema/jee
 http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
 http://www.springframework.org/schema/util
 http://www.springframework.org/schema/util/spring-util-3.0.xsd"
 default-autowire="byName">

 <context:component-scan base-package="com.XXX" />
 <context:annotation-config />
 <tx:annotation-driven />
 <tx:jta-transaction-manager />

 <jee:jndi-lookup id="XXXCgDataSource" jndi-name="XXXCgDataSource"
  lookup-on-startup="true" />

 <bean id="entityManager"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="dataSource" ref="XXXCgDataSource" />
  <property name="persistenceUnitName" value="XXXPU" />
 </bean>

 <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
  <property name="entityManagerFactory" ref="entityManager" />
  <property name="dataSource" ref="XXXCgDataSource" />
 </bean>

 <!-- JNDI Lookup -->
 <jee:jndi-lookup id="xxxServiceBean"
  jndi-name="java:global/XXX-cg-ear-0.0.1-SNAPSHOT/XXX-cg-ejbs/XXXServiceBean"
  resource-ref="true" lookup-on-startup="true"
  expected-type="com.XXX.cg.service.xxx.local.XXXServiceBeanLocal"
  proxy-interface="com.XXX.cg.service.xxx.local.XXXServiceBeanLocal" />

 <!-- Load in application properties reference -->
 <bean id="propertiesBean" name="propertiesBean"
  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="location" value="/XXX-cg.properties" />
 </bean>

 <bean id="LogginInjector" class="com.XXX.commons.logger.LoggerPostProcessor" />
</beans>
The class where the stateless EJB is being called
@Path("/XXX")
@Component
public class XXXServiceImpl {
 @Log
 private Logger log;
 
 @EJB
 protected XXXServiceBeanLocal XXXServiceBean;

 @POST
 @Path("/register")
 @Produces({ MediaType.APPLICATION_JSON })
 public Response register(@FormParam("email") String email,
   @FormParam("macid") String macid, @FormParam("type") String type) {
  //...
  String reply = XXXServiceBean.register(email, macid, type);
  //...
  return resp;
 }
}
And that's it for the web project. And for the ejb project we have:
beanRefContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

 <bean id="com.sido"
  class="org.springframework.context.support.ClassPathXmlApplicationContext">
  <constructor-arg>
   <list>
    <value>ejbApplicationContext.xml</value>
   </list>
  </constructor-arg>
 </bean>
</beans>
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.0.xsd
 http://www.springframework.org/schema/jee
 http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
 default-autowire="byName">

 <context:annotation-config />
 <context:component-scan base-package="com.XXX" />
 <tx:annotation-driven />

 <jee:jndi-lookup id="XXXCgDataSource" jndi-name="XXXCgDataSource"
  lookup-on-startup="true" />

 <bean id="entityManager"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="dataSource" ref="XXXCgDataSource" />
  <property name="persistenceUnitName" value="XXXPU" />
 </bean>

 <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
  <property name="entityManagerFactory" ref="entityManager" />
  <property name="dataSource" ref="XXXCgDataSource" />
 </bean>

</beans>
ejb-jar.xml
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee" xmlns:ejb="http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
 version="3.1">

 <!-- <display-name>XXX-cg-ejbs</display-name> -->
 <module-name>XXX-cg-ejbs</module-name>

 <interceptors>
  <interceptor>
   <interceptor-class>org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor</interceptor-class>
  </interceptor>
 </interceptors>
 <assembly-descriptor>
  <interceptor-binding>
   <ejb-name>*</ejb-name>
   <interceptor-class>org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor</interceptor-class>
  </interceptor-binding>
 </assembly-descriptor>
</ejb-jar>
The actual interface and class XXX interface
/**
 * @author czetsuya
 * @created May 4, 2012
 **/
package com.sido.cg.service.XXX.local;

import javax.ejb.Local;

@Local
public interface XXXServiceBeanLocal {
 String register(String email, String macId, String type);
 String create(String email, String macId, String type);
}
XXX class
/**
 * @author Edward P. Legaspi
 * @created May 4, 2012
 **/
package com.sido.cg.service.XXX;

import javax.ejb.Stateless;
import javax.interceptor.Interceptors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor;

import com.sido.cg.service.XXX.local.XXXServiceBeanLocal;

@Interceptors(SpringBeanAutowiringInterceptor.class)
@Stateless
public class XXXServiceBean implements XXXServiceBeanLocal {
 @Autowired
 private XXXService XXXService;

 public String register(String email, String macId, String type) {
  return XXXService.register(email, macId, type);
 }

 public String create(String email, String macId, String type) {
  return XXXService.create(email, macId, type);
 }

}
And I believe that's all you need to call a stateless ejb from another web project powered by spring. Take note that you can also inject spring bean from the ejb stateless bean using SpringBeanAutowiringInterceptor.
How to call a stateless EJB from a spring rest servlet component How to call a stateless EJB from a spring rest servlet component Reviewed by Edward Legaspi on Monday, May 28, 2012 Rating: 5

No comments:

Powered by Blogger.