Showing posts with label Spring. Show all posts
Showing posts with label Spring. Show all posts

Sunday, April 19, 2009

Testing EJB out of application server - Part 3. Spring managed DAO tier

After a short delay and thinking about giving Spring to manage stateless DAO tier beans, here comes 3-rd part of the article. There were some issues that had to be investigated to make the topic complete. Most of all, there was an open question of controlling Hibernate Session
life cycle, to have OpenSessionInView pattern working.
Let's define what we want to gain with DAO bean management by Spring:
1. Keep DAO beans working with EntityManager to make CRUD operations with entities.
2. Make switch from EJB' @Stateless (and even @Stateful) annotations to Spring' @Service (or have beans configured in XML file).
3. Have bean auto wiring in DAO with Spring IoC, avoiding JNDI lookups and extra configuration in XML file.
4. Ensure transaction and session management is compliant with EJB approach to handle entity beans lazy initialization problem (here I refer to interceptor and callback/template approaches).

Let's examine what changes are to be done to our simple Internet shop application.

DAO tier


Since we do not need to manage DAO beans with EJB but Spring, just change annotations on DAO bean class level:

@Service("purchaseDAO")
public class PurchaseDAOImpl extends AbstractDAO<Purchase> implements PurchaseDAO {
public PurchaseDAOImpl() {
super(Purchase.class);
}
}


Here, we used @Service that is recognized by Spring component scanning functionality we already familiar with. Also, DAO interfaces do not need @Local nor @Remote annotation (so they are removed):

public interface PurchaseDAO extends DAO<Purchase> {
}


There is also a simplification in application context configuration file - DAO beans refering through JNDI to stateful beans managed by EJB have been removed.
Important configuration step is adding <context:annotation-config/> to application context configuration file. This will include support for JPA annotations like @PersistenceContext. To have everything working we need to define bean, with name of persistence unit, which refers to EntityManagerFactory:

<bean id="entityManagerFactory"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject"
ref="entityManagerBean"/>
<property name="targetMethod"
value="getEntityManagerFactory"/>
</bean>

<alias alias="ishopPU"
name="entityManagerFactory"/>


OpenSessionInView pattern


To be correct, in Spring terms pattern is named OpenEntityManagerInView. There is a significant difference between this new approach and old-style one used by applications, built upon Hibernate ORM, to keep Hibernate Session open for a request processing cycle.
Opening Hibernate Session in filter and binding it to SessionFactory these applications relied on the fact entity beans extracted in DAO tier are kept attached to this session until request has been processed and session is closed, so access to lazily initialized references would not cause an exception.
But the approach, in it's original implementation, does not work for EJB - each transactional method is completed within its own EntityManager instance which holds reference to it's distinct Hibernate Session; opening new session does not make any affect.
Instead, using TransactionSynchronizationManager, we bind EntityManager to EntityManagerFactory so each transactional method executed with the same EntityManager, and as result the same Session, instance used:

@Stateful(name = "openSessionInViewCallback")
@LocalBinding(jndiBinding = "openSessionInViewCallbackLocal")
public class OpenSessionInViewCallbackImpl implements OpenSessionInViewCallback {
@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;

@PersistenceUnit(unitName = "ishopPU")
private EntityManagerFactory entityManagerFactory;

@Init
public void invoke(Runnable r) {
TransactionSynchronizationManager.bindResource(entityManagerFactory, new EntityManagerHolder(entityManager));

r.run();
}

@Remove
public void remove() {
TransactionSynchronizationManager.unbindResource(entityManagerFactory);
EntityManagerFactoryUtils.closeEntityManager(entityManager);
}
}


In @Init method we bind entity manager, and unbind it on callback method completion with @Remove cleanup. For more information on Spring implementation of the pattern please refer to org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter and org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor

Source code


Can be downloaded here.

That's it!

Sunday, April 5, 2009

Testing EJB out of application server - Part 2. Integrating Spring

The aim


In Part 1 I mentioned Spring's transaction management API. I believe this is quite a serious reason to think about integrating Spring framework into EJB application. But not the only one. Spring provides easy way to maintain multiple application configurations with IoC making testing configuration of your application independent of production one. Other features, like JNDI support, integration with JMS, JMX, mail and other services make the framework so popular.
Returning to our internet shop application we have to decide what we want to leave managed by EJB and what we want to put under Spring's control, and look at other options we have.

Data access. We considered JPA as an appropriate way to configure entity and DAO beans that provide basic functionality to access former. DAO stateless beans usually do not depend upon any other application tier, and really seldom use each other; EntityManager gives all an ordinal DAO needs.

Business services. This is really a good place Spring may take care of. Injecting dependencies on other beans (e.g. DAOs), configuration parameters provided within application configuration files, managing transactions is where Spring really strong. Moreover, with Spring testing module we can use these features directly in test classes.

Web services. JSR-181 defines API that is available within stateless beans to define them as providing Web services methods. EJB3 greatly supports this API, and though there is an option to use XFire framework together with Spring, to configure Web services, I see no reason to keep away from standard. Sometimes it is better avoid getting deep into framework hell. Though not always :)

Sample application changes


Domain tier


It is not a surprise that there is nothing to be changed. Entity beans still use JPA for O/R mapping that is controlled by EJB container.

Data access tier


There is one thing that needs to be done to each DAO implementation bean. Since we are going to publish DAO stateless beans in JNDI, so they will be available to Spring, we will use @LocalBinding JBoss annotation to provide bean JNDI name for production environment, as follows:
@Stateless(name = "productDAO")
@LocalBinding(jndiBinding = "productDAOLocal")
public class ProductDAOImpl extends AbstractDAO<Product> implements ProductDAO {
// methods implementations
}

Every DAO bean is configured in application context configuration file like this one:
<jee:jndi-lookup id="productDAO"
proxy-interface="org.ishop.dao.ProductDAO"
jndi-name="productDAOLocal"/>

Unfortunatelly I do not know if there is any way to avoid this, like using automatic scanning.

Service tier


Minor changes should be done to service methods - to switch to Spring transaction API we change @TransactionAttribute to @Transactional and specify other options, if needed. Also dependency injection is now controlled by Spring, based on bean name or type wiring, or on @Autowired annotation:
@Service("productService")
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductDAO productDAO;
@Autowired
private PurchaseDAO purchaseDAO;

@Transactional
public void save(Product product) {
productDAO.save(product);
}

@Transactional(readOnly = true)
public Product getProduct(Long id) {
return productDAO.get(id);
}

@Transactional
public Purchase purchase(Long productId, Date paymentDate) {
// method implementation
}
}

Please notice that we used @Service that allows us to skip configuring bean in application context configuration file, relying on auto-detection option:

We need to configure transaction management - Spring will use container JTA transaction manager to which it will redirect all transaction processing requests, based on own transaction annotations support and handling:
<bean class="org.springframework.transaction.aspectj.AnnotationTransactionAspect"
factory-method="aspectOf">
<property name="transactionManager"
ref="platformTransactionManager"/>
</bean>

<bean id="platformTransactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"/>

Here we configured aspect to support @Transactional annotations. One principal change is made to the build script - Java classes are processed by AspectJ compiler. Another option is use dynamic proxies that will do the same thing. One significant disadvantage of this approach is that to handle calls between business methods of the same service properly they should be made through the proxy.
One more good thing about Spring transaction management API is that service method may throw any exception (checked or unchecked). Instead of annotating exception class with @ApplicationException as EJB spec requires, in @Transactional annotation parameters we may specify which exception(s) should cause transaction rollback and which will lead to commit. Really nice.

Web services


As well as within business tier, Web service need just minor changes in API - replacement of @EJB with @Autowired and adding SpringContextInterceptor interceptor to the list of method call interceptors:
@Interceptors({SpringContextInterceptor.class, OpenSessionInViewInterceptor.class})
public class ProductWebServiceImpl implements ProductWebService {
@Autowired
private ProductService productService;
// methods skipped
}

SpringContextInterceptor is responsible for application context startup when application Web service accessed the first time.
public class SpringContextInterceptor extends SpringBeanAutowiringInterceptor {
private BeanFactory beanFactory;

protected BeanFactory getBeanFactory(Object o) {
if (beanFactory == null) {
beanFactory = new ClassPathXmlApplicationContext("/applicationContext.xml").getAutowireCapableBeanFactory();
}
return beanFactory;
}

@PreDestroy
@PrePassivate
public void releaseBean(InvocationContext invocationContext) {
super.releaseBean(invocationContext);
}

@PostConstruct
@PostActivate
public void autowireBean(InvocationContext invocationContext) {
super.autowireBean(invocationContext);
}
}


Changes to unit tests


Spring provides a module to support bean wiring into test classes for both jUnit and TestNG. What we need to change in AbstractPersistenceTest is set up application context and remove lookup() method since we do not rely on bean wiring with EJB:
@ContextConfiguration(locations = {"classpath:/test-applicationContext.xml"})
public abstract class AbstractPersistenceTest extends AbstractTestNGSpringContextTests {
@BeforeClass(groups = "database")
public final void setUpDatabase() throws NamingException, IOException {
Properties props = new Properties();
props.load(AbstractPersistenceTest.class.getResourceAsStream("/persistence.properties"));
new InitialContext(props);
}

@BeforeClass(dependsOnMethods = "setUpDatabase")
protected void springTestContextPrepareTestInstance() throws Exception {
super.springTestContextPrepareTestInstance();
}
}

Here method springTestContextPrepareTestInstance has been overriden to be called when EJB container has been set up by setUpDatabase().
Testing code does not need serious changes as well as production code does not - use dependency injection with @Autowired instead of looking up for required resource in JNDI.
I strongly believe Spring offers a lot of features which when used in enterprise level applications may reduce coupling of beans and tiers, making daily development and testing easier.

Source code


ishop.ejb-testng-spring.zip

Thanks you!