CXF is a opensource framework implementing JAX-WS and JAX-RS.

Minuteproject 4 REST-CXF provides CXF framework with artifacts from a data model reverse-engineering.
CXF generated artifacts are built on top of BSLA DAO stack and JPA2 track, the glue is done by spring configuration.

The generated artefacts are packaged in 4 maven projects
  • One global for JPA2, BSLA DAO, CXF REST
  • One for JPA2 (see JPA2 for details regarding jpa2 annotations, and jaxb annotations)
  • One for BSLA DAO
  • One for CXF REST (cxf implementation)

The dedicated artifacts for CXF are
  • At model level
    • spring application context
    • web.xml
  • At entity level
    • CXF resource bean

The DAOs, spring configuration, JPA2 and other backend aspect are generate from associated tracks.

To have a sample please check what is generated in mp-source-generated-0.7.zip+ folder cxf

Generation Step

The 'Generation step' consists of configuring MP kernel either via a configuration file or via the console.

Prequisites

Have Java 6 setup.
Download MinuteProjectlast version.
Check that your database connection is available

Generation Via the console

  1. Start the MP console (<MP_HOME>/bin/start-console.(cmd/sh). How to use the console.
  2. Fill the connection information to the datamodel
  3. Fill the model general information (model, package names, version primary key policy, scope).
  4. Choose CXF target
  5. Click generate

Generation Via the configuration file and command line

An example can be found <MP_HOME>/demo/config/mp-config-REST-CXF-Spring.xml
mp-config-REST-CXF-Spring.xml references the shipped petshop database (<MP_HOME>/sample).

To run it, execute demo-REST-CXF-Spring-tech.(cmd/sh)

Configuration

mp-config-REST-CXF-Spring.xml is the configuration holding
  • data model specific location as well as 'enrichement' feature
  • techno tracks (Spring, hibernate, JPA2, CXF...) to use
<!DOCTYPE root>
<generator-config>
    <configuration>
        <conventions>
            <target-convention type="enable-updatable-code-feature" />
        </conventions>
        <model name="petshop" version="1.0" package-root="net.sf.mp.demo.jpa2">
            <data-model>
                <driver name="hsqldb" version="1.8.0.7" groupId="hsqldb" artifactId="hsqldb"/>
                <fileSource name="petshop" dir="c:/MinuteProject/data">
                </fileSource>
                <dataSource>
                    <driverClassName>org.hsqldb.jdbcDriver</driverClassName>
                    <url>jdbc:hsqldb:hsql://127.0.0.1:9001/petshop</url>
                    <username>sa</username>
                    <password></password>
                </dataSource>
                <!-- for Oracle and DB2 please set the schema
                <schema> </schema>
                 -->
                <primaryKeyPolicy oneGlobal="true" oneForEachTable="false">
                    <primaryKeyPolicyPattern prefix="" suffix=""
                     name="sequencePattern" sequenceName="hibernate_sequence"/>
                </primaryKeyPolicy>
            </data-model>
            <business-model>
                <generation-condition>
                    <condition type="exclude" startsWith="DUAL"></condition>
                    <condition type="exclude" startsWith="ID_GEN"></condition>
                </generation-condition>
                <business-package default="pet">
                    <condition type="package" startsWith="PRODUCT" result="product"></condition>
                    <condition type="package" startsWith="ITEM" result="product"></condition>
                </business-package>
                <enrichment>
                   <conventions>
                      <entity-naming-convention type="apply-strip-table-name-prefix"
                         pattern-to-strip="SYS,FIN"/>
                      <column-naming-convention
                                    type="apply-fix-primary-key-column-name-when-no-ambiguity"
                                    default-value="ID"/>
                      <reference-naming-convention type="apply-referenced-alias-when-no-ambiguity"
                             is-to-plurialize="true"></reference-naming-convention>
                   </conventions>
                    <package name="product">
                        <entity-group entities="PRODUCT"></entity-group>
                        <entity-group entities="ITEM"></entity-group>
                    </package>
                    <entity name="PRODUCT" alias="MY_GOOD_PRODUCT">
                    </entity>
                    <entity name="ITEM" alias="MY_GOOD_ITEM" comment="my item table">
                        <field name="PRODUCTID" alias="THIS_IS_MY_PRODUCT"
                              comment="my product field reference"></field>
                    </entity>
                    <entity name="CATEGORY" content-type="reference-data" >
                       <semantic-reference>
                         <sql-path path="NAME"/>
                       </semantic-reference>
                    </entity>
                </enrichment>
            </business-model>
        </model>
        <targets catalog-entry="REST-CXF-Spring"/>
    </configuration>
</generator-config>
 
The main points relevant for CXF are:
Enabling updatable feature: the code containing updatable part will be handled
<target-convention type="enable-updatable-code-feature" />
Concretely this means you can change CXF Resource artifacts generated.


Generated artifacts

Here only the artifacts CXF specifics are mentionned

Structure

rest-cxf-pom-structure.png

Detail

Resource entity

Exemple: AddressResource
package net.sf.mp.demo.jpa2.petshop.rest.pet;
 
 
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.io.*;
import java.sql.*;
 
import javax.servlet.http.*;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
 
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.FormParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.xml.bind.JAXBElement;
 
import net.sf.mp.demo.jpa2.petshop.dao.face.pet.AddressDao;
import net.sf.mp.demo.jpa2.petshop.dao.face.pet.AddressExtDao;
import net.sf.mp.demo.jpa2.petshop.domain.pet.Address;
 
/**
 *
 * <p>Title: AddressResource</p>
 *
 * <p>Description: remote interface for AddressResource service </p>
 *
 */
@Path ("/rest/xml/addresses")
@Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Consumes ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Service
@Transactional
public class AddressResource  {
 
 
    @Autowired
    @Qualifier("addressDao")
    AddressDao addressDao;
 
    @Autowired
    @Qualifier("addressExtDao")
    AddressExtDao addressExtDao;
 
//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @FIND_ALL-ADDRESS@
    @GET
    @Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    public List<Address> findAll () {
    List<Address> r = new ArrayList<Address>();
        List<Address> l = addressDao.searchPrototypeAddress(new Address());
    for (Address address : l) {
        r.add(address.flat());
    }
    return r;
    }
//MP-MANAGED-UPDATABLE-ENDING
 
//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @FIND_BY_ID-ADDRESS@
    @GET
    @Path("{id}")
    @Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    public Address findById (@PathParam ("id") java.lang.Integer id) {
        Address _address = new Address ();
    _address.setId(id);
    _address = addressExtDao.getFirstAddress(_address);
    if (_address!=null) return _address.flat();
    return new Address ();
    }
//MP-MANAGED-UPDATABLE-ENDING
 
    @DELETE
    @Path("{id}")
    public void delete (@PathParam ("id") Integer id) {
        Address address = new Address ();
        address.setId(id);
        addressDao.deleteAddress(address);
    }
 
    @POST
    @Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public Address create (
        @FormParam("id") Integer id,
        @FormParam("street1") String street1,
        @FormParam("street2") String street2,
        @FormParam("city") String city,
        @FormParam("state") String state,
        @FormParam("zip") String zip,
        @FormParam("latitude") java.math.BigDecimal latitude,
        @FormParam("longitude") java.math.BigDecimal longitude,
        @Context HttpServletResponse servletResponse
        ) throws IOException {
        Address _address = new Address (
           id,
           street1,
           street2,
           city,
           state,
           zip,
           latitude,
           longitude);
        return save(_address);
    }
 
    @PUT
    @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    public Address save(JAXBElement<Address> jaxbAddress) {
        Address address = jaxbAddress.getValue();
        if (address.getId()!=null)
            return addressDao.updateAddress(address);
        return save(address);
    }
 
    public Address save (Address address) {
        addressDao.saveAddress(address);
        return address;
    }
}
The main points are:
  • define access path
  • define format
  • provide CRUD access to entities
  • use BSLA DAO

Spring application-context

<?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:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:jaxrs="http://cxf.apache.org/jaxrs"
    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/tx
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://cxf.apache.org/jaxrs
        http://cxf.apache.org/schemas/jaxrs.xsd">
 
    <import resource="classpath:META-INF/cxf/cxf.xml" />
    <import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" />
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
 
    <context:component-scan base-package="net.sf.mp.demo.jpa2.petshop.rest"/>
 
    <import resource="classpath:net/sf/mp/demo/jpa2/petshop/factory/spring/spring-config-Petshop-BE-main.xml"/>
 
    <jaxrs:server id="restContainer" address="/">
        <jaxrs:serviceBeans>
            <!-- pet -->
            <ref bean="addressResource"/>
            <ref bean="categoryResource"/>
            <ref bean="sellercontactinfoResource"/>
            <ref bean="tagResource"/>
            <ref bean="ziplocationResource"/>
            <!-- product -->
            <ref bean="myGoodItemResource"/>
            <ref bean="myGoodProductResource"/>
 
        </jaxrs:serviceBeans>
    </jaxrs:server>
 
</beans>
The main points are:
Import BSLA stack backend DAO
    <import resource="classpath:net/sf/mp/demo/jpa2/petshop/factory/spring/spring-config-Petshop-BE-main.xml"/>
Reference service resource beans
    <jaxrs:server id="restContainer" address="/">
        <jaxrs:serviceBeans>
            <!-- pet -->
            <ref bean="addressResource"/>
...

Servlet web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 
    <display-name>petshop CXF REST</display-name>
    <description>petshop CXF REST access</description>
 
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/application-context.xml</param-value>
    </context-param>
 
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
 
    <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
 
</web-app>

Packaging-deployment

Interventions

Tomcat dependency

There is a little trick here. The deployment is on tomcat.
Tomcat by default do not support JTA transactions.
But the resulting persistence.xml code generated with
<!--MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @PERSISTENCE-UNIT-petshop@-->
    <persistence-unit name="petshop" transaction-type="JTA">
<!--MP-MANAGED-UPDATABLE-ENDING-->
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
<!--MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @DATASOURCE-petshop@-->
        <jta-data-source>jdbc/petshopDS</jta-data-source>
<!--MP-MANAGED-UPDATABLE-ENDING-->
will not work.
The code has to be altered:
  • to run for non-jta data source
  • to keep this alteration over other reverse-engineering executions.
<!--MP-MANAGED-UPDATABLE-BEGINNING-ENABLE @PERSISTENCE-UNIT-petshop@-->
    <persistence-unit name="petshop" >
<!--MP-MANAGED-UPDATABLE-ENDING-->
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
<!--MP-MANAGED-UPDATABLE-BEGINNING-ENABLE @DATASOURCE-petshop@-->
        <non-jta-data-source>jdbc/petshopDS</non-jta-data-source>
<!--MP-MANAGED-UPDATABLE-ENDING-->

BSLA dependency

Bsla jar is not deployed in maven central yet but shipped with minuteproject. It is needed by the project Bsla DAO.
Go to <MP_HOME>/target/bsla
Run install_bsla(sh/cmd)

Packaging

On <MP_HOME>/demo/output/cxf/petshop run:
mvn package
It will create the
  • JPA2 backend
  • BSLA DAO layer
  • REST CXF API
The result app war petshopRestCxfApp.war is in <MP_HOME>/demo/output/cxf/petshop/rest/target.

Deployment

On tomcat
  • add connexion pool snippet
    <Resource name="jdbc/petshopDS" auth="Container" type="javax.sql.DataSource"
       maxActive="20" maxIdle="5" maxWait="10000"
       username="sa" password="" driverClassName="org.hsqldb.jdbcDriver"
       url="jdbc:hsqldb:hsql://127.0.0.1:9001/petshop"/>
  • deploy petshopRestCxfApp.war

Testing

Select all

rest-cxf-addresses.png

Select one

rest-cxf-address-one.png

Create

rest-cxf-address-create.png

Update

rest-cxf-address-update.png

Delete

With curl
curl -X DELETE http://localhost:8080/petshopRestCxfApp/rest/xml/addresses/152

Knowledge sources


http://cxf.apache.org/docs/jax-rs.html

http://www.insaneprogramming.be/?p=140

http://dhruba.name/2008/12/08/rest-service-example-using-cxf-22-jax-rs-10-jaxb-and-spring/

http://www.baeldung.com/2011/10/25/building-a-restful-web-service-with-spring-3-1-and-java-based-configuration-part-2/

http://www.ibm.com/developerworks/web/library/wa-restful/

http://stackoverflow.com/questions/852969/what-is-the-minimal-configuration-for-rest-fully-annotated-service-built-on-spri

http://java.dzone.com/articles/spring-30-rest-example