JBoss Trading – Java EE 5 to Java EE 6 Migration Part I (CDI 1.0 & JAX-RS 1.1)

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.

  1. Remove the JAX-RS dependency.
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>jaxrs-api</artifactId>
        <version>${resteasy.version}</version>
    </dependency>
  2. Remove the JAX-RS annotations from TradeManager.
  3. 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.

  1. 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>
  2. Remove the JBoss Trading RESTEasy JAX-RS dependency.
    <dependency>
        <groupId>com.jboss.trading</groupId>
        <artifactId>trading-resteasy-jaxrs</artifactId>
        <version>${project.version}</version>
    </dependency>
  3. 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

  • 2.3.2 – Servlet (link)
  • 6.2 – Java EE Container (link)
  1. Configure the Maven WAR build plugin.
    <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.1.1</version>
        <configuration>
            <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
    </plugin>
  2. Add the JBoss Trading API dependency.
    <dependency>
        <groupId>com.jboss.trading</groupId>
        <artifactId>trading-api</artifactId>
        <version>${project.version}</version>
        <scope>provided</scope>
    </dependency>
  3. 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>
  4. WEB-INF/web.xml (delete)
  5. 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" />
  6. 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 {
    }
  7. 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.

  1. 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>
  2. trading-queue-service.xml (delete)
  3. 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>
  4. 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" />
  5. 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>
  6. TradeManagerBean.java (update)
    import org.jboss.wsf.spi.annotation.WebContext;
    
    @WebContext(contextRoot = "/trading")
    
    @Resource(mappedName = "java:/queue/jbossTradingLimitOrders")
    
    @Resource(mappedName = "java:/ConnectionFactory")
  7. 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)
, , , , ,

About Shane K Johnson

Technical Marketing Manager, Red Hat Inc.

View all posts by Shane K Johnson

No comments yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 118 other followers

%d bloggers like this: