This post is the first in a series that covers the Java EE 5 to Java EE 6 migration of the JBoss Trading application (link).
This post covers the impact of CDI 1.0 and JAX-RS 1.1 on the architecture and the source code / configuration modifications required to implement it.
Architecture
The application architecture defines a loosely coupled, modular application.
The Java EE 5 version of the JBoss Trading application (link) exposes REST and web services by annotating an EJB with JAX-RS and JAX-WS annotations.
The Java EE 6 version of the JBoss Trading application (link) exposes REST services by injecting an EJB into a JAX-RS annotated POJO and web services by injecting an EJB into a JAX-WS annotated POJO.
Source Code / Configuration
JBoss Trading API
The JAX-RS annotations on the business interface are no longer required as they no longer need to be inherited by the EJB from the JBoss Trading Services module.
- Remove the JAX-RS dependency.
<dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>jaxrs-api</artifactId> <version>${resteasy.version}</version> </dependency> - Remove the JAX-RS annotations from TradeManager.
- Move the exception mappers to a new package (com.jboss.trading.rest.mapper) in JBoss Trading REST.
JBoss Trading App
The application is packaged as a Java EE 6 application. The version number will not be included in the file names of the EAR modules and / or libraries. The JBoss Trading RESTEasy JAX-RS module is no longer required as a dependency as the fix to allow an EJB to inherit JAX-RS annotations from a business interface is no longer needed. The RESTEasy dependencies are no longer required as JAX-RS is a part of Java EE 6.
- Update the Maven EAR plugin configuration.
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-ear-plugin</artifactId> <version>2.7</version> <configuration> <version>6</version> <defaultLibBundleDir>lib</defaultLibBundleDir> <fileNameMapping>no-version</fileNameMapping> </configuration> </plugin> - Remove the JBoss Trading RESTEasy JAX-RS dependency.
<dependency> <groupId>com.jboss.trading</groupId> <artifactId>trading-resteasy-jaxrs</artifactId> <version>${project.version}</version> </dependency> - Remove the RESTEasy dependencies.
<dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jackson-provider</artifactId> <version>${resteasy.version}</version> </dependency> <dependency> <groupId>org.scannotation</groupId> <artifactId>scannotation</artifactId> <version>${scannotation.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${slf4j.version}</version> </dependency>
JBoss Trading REST
The web.xml file is no longer required with a JAX-RS Application subclass annotated with @ApplicationPath and @ApplicationScoped. The EJB is injected into a JAX-RS annotated POJO using CDI with the business interface from the JBoss Trading API module and a qualifier. An empty beans.xml file is required for CDI.
JAX-RS 1.1
- Configure the Maven WAR build plugin.
<plugin> <artifactId>maven-war-plugin</artifactId> <version>2.1.1</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> - Add the JBoss Trading API dependency.
<dependency> <groupId>com.jboss.trading</groupId> <artifactId>trading-api</artifactId> <version>${project.version}</version> <scope>provided</scope> </dependency> - Add the Java EE 6 (CDI / JAX-RS) dependencies.
<dependency> <groupId>javax.enterprise</groupId> <artifactId>cdi-api</artifactId> <version>1.0-SP4</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.jboss.spec.javax.ws.rs</groupId> <artifactId>jboss-jaxrs-api_1.1_spec</artifactId> <version>1.0.1.Final</version> <scope>provided</scope> </dependency> - WEB-INF/web.xml (delete)
- WEB-INF/beans.xml (create)
<?xml version="1.0"?> <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://jboss.org/schema/cdi/beans_1_0.xsd" />
- TradingApplication.java (create)
package com.jboss.how.to.polling.rest; import javax.enterprise.context.ApplicationScoped; import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; @ApplicationPath("/trading") @ApplicationScoped public class TradingApplication extends Application { } - TradingServices.java (create)
package com.jboss.trading.rest; import com.jboss.trading.api.TradeManager; import com.jboss.trading.api.exception.LimitOrderNotFoundException; import com.jboss.trading.api.exception.MarketOrderNotFoundException; import com.jboss.trading.api.exception.PlaceOrderException; import com.jboss.trading.api.model.LimitOrder; import com.jboss.trading.api.model.MarketOrder; import com.jboss.trading.api.model.TransactionType; import java.util.List; import javax.inject.Inject; import javax.inject.Named; import javax.ws.rs.DELETE; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; @Path("/services") public class TradingServices { @Inject @Named("TradeManagerBean") TradeManager tradeManager; @DELETE @Path("/orders/limit/{limitOrderId}") @Produces("application/json") public void cancelLimitOrder( @PathParam("limitOrderId") Integer limitOrderId) throws LimitOrderNotFoundException { tradeManager.cancelLimitOrder(limitOrderId); } @DELETE @Path("/orders/market/{marketOrderId}") @Produces("application/json") public void cancelMarketOrder( @PathParam("marketOrderId") Integer marketOrderId) throws MarketOrderNotFoundException { tradeManager.cancelMarketOrder(marketOrderId); } @POST @Produces("application/json") @Path("/orders/limit") public void placeLimitOrder( @FormParam("stockHolderId") Integer stockHolderId, @FormParam("transactionType") TransactionType transactionType, @FormParam("quantity") Integer quantity, @FormParam("stockSymbol") String stockSymbol, @FormParam("price") Float price) throws PlaceOrderException { tradeManager.placeLimitOrder( stockHolderId, transactionType, quantity, stockSymbol, price); } @POST @Produces("application/json") @Path("/orders/market") public void placeMarketOrder( @FormParam("stockHolderId") Integer stockHolderId, @FormParam("transactionType") TransactionType transactionType, @FormParam("quantity") Integer quantity, @FormParam("stockSymbol") String stockSymbol) { tradeManager.placeMarketOrder( stockHolderId, transactionType, quantity, stockSymbol); } @GET @Path("/orders/limit/{limitOrderId}") @Produces("application/json") public LimitOrder viewLimitOrder( @PathParam("limitOrderId") Integer limitOrderId) throws LimitOrderNotFoundException { return tradeManager.viewLimitOrder(limitOrderId); } @GET @Path("/orders/market/{marketOrderId}") @Produces("application/json") public MarketOrder viewMarketOrder( @PathParam("marketOrderId") Integer marketOrderId) throws MarketOrderNotFoundException { return tradeManager.viewMarketOrder(marketOrderId); } @GET @Path("/stockholders/{stockHolderId}/orders/limit/last/{numberLimitOrders}") @Produces("application/json") public List<LimitOrder> viewStockHolderLimitOrders( @PathParam("stockHolderId") Integer stockHolderId, @PathParam("numberLimitOrders") Integer numberLimitOrders) { return tradeManager.viewStockHolderLimitOrders( stockHolderId, numberLimitOrders); } @GET @Path("/stockholders/{stockHolderId}/orders/market/last/{numberLimitOrders}") @Produces("application/json") public List<MarketOrder> viewStockHolderMarketOrders( @PathParam("stockHolderId") Integer stockHolderId, @PathParam("numberLimitOrders") Integer numberMarketOrders) { return tradeManager.viewStockHolderMarketOrders( stockHolderId, numberMarketOrders); } }
JBoss Trading Services
A few modifications are required to deploy to JBoss EAP 6.
- JMS queues are configured with a *-jms.xml file.
- The default data source is “java:jboss/datasources/ExampleDS”.
- Infinispan is the default JPA second level cache provider.
- The prefix for global JNDI names is “java:/”.
The @WebContext annotation is no longer required. An empty beans.xml file is required for CDI.
For clarity, a producer method with a qualifier is created for the business interface.
- Add the Java EE 6 (CDI) dependencies.
<dependency> <groupId>javax.enterprise</groupId> <artifactId>cdi-api</artifactId> <version>1.0-SP4</version> <scope>provided</scope> </dependency> - trading-queue-service.xml (delete)
- META-INF/trading-jms.xml (create)
<?xml version="1.0" encoding="UTF-8"?> <messaging-deployment xmlns="urn:jboss:messaging-deployment:1.0"> <hornetq-server> <jms-destinations> <jms-queue name="jbossTradingLimitOrders"> <entry name="/queue/jbossTradingLimitOrders"/> </jms-queue> </jms-destinations> </hornetq-server> </messaging-deployment>
- META-INF/beans.xml (create)
<?xml version="1.0"?> <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://jboss.org/schema/cdi/beans_1_0.xsd" />
- META-INF/persistence.xml (update)
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <persistence-unit name="trading" transaction-type="JTA"> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <class>com.jboss.trading.services.persistence.LimitOrderEntity</class> <class>com.jboss.trading.services.persistence.MarketOrderEntity</class> <class>com.jboss.trading.services.persistence.StockEntity</class> <class>com.jboss.trading.services.persistence.StockHolderEntity</class> <properties> <property name="hibernate.hbm2ddl.auto" value="${hibernate.hbm2ddl.auto}" /> <property name="hibernate.cache.use_second_level_cache" value="true" /> <property name="hibernate.cache.use_query_cache" value="true" /> </properties> </persistence-unit> </persistence> - TradeManagerBean.java (update)
import org.jboss.wsf.spi.annotation.WebContext;@WebContext(contextRoot = "/trading")@Resource(mappedName = "java:/queue/jbossTradingLimitOrders") @Resource(mappedName = "java:/ConnectionFactory") - Resources.java (create)
package com.jboss.trading.services.util; import com.jboss.trading.api.TradeManager; import com.jboss.trading.services.TradeManagerLocal; import javax.ejb.EJB; import javax.enterprise.inject.Produces; import javax.inject.Named; public class Resources { @EJB TradeManagerLocal tradeManager; @Produces @Named("TradeManagerBean") public TradeManager getTradeManager() { return tradeManager; } }
Build
mvn clean package -Plocalhost-remote -DskipTests
JBoss Trading – Java EE 5 to Java EE 6 Migration
- Part I – CDI 1.0 & JAX-RS 1.1
- Part II – JPA 2.0 & JAX-WS 2.2 (link)
- Part III – Structure & Packaging (link)
- Part IV – Deployment & Testing (link)
- Part V – Clean Up (link)

