Showing posts with label MAVEN. Show all posts
Showing posts with label MAVEN. Show all posts

Wednesday, June 13, 2012

How to create a simple CXF based JAX-RS Client

 
In my previous blog post, I did explain how to create a REST API using CXF and Spring.

This time I would like to describe how to quickly create a client that can call the REST API while reusing the resources POJO classes,
so the un-marshalling is done by JAXB.

For this I am using the CXF WebClient which is very simple to use:

  • import WebClient from org.apache.cxf.jaxrs.client.WebClient
  • import your POJOs
  • import a JABX provider (I am using Jackson JAXB JSON provider)

 Here is a very simple standalone program that does exactly this (make sure your REST API has been deployed locally):
 
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import org.apache.cxf.jaxrs.client.WebClient;
import java.util.ArrayList;
import java.util.List;

public class App 
{
    public static void main( String[] args )  throws Exception { 
      
     List<Object> providers = new ArrayList<Object>();
     providers.add( new JacksonJaxbJsonProvider() );
   
     WebClient client = WebClient.create("http://localhost:8080/poc_restapi_cxf/api", providers);
     client = client.accept("application/json").type("application/json").path("/order").query("id", "1");
   
     Order order = client.get(Order.class);
     System.out.println("Order:" + order.getCustomerName());
  
    }
}
With this very simple client program, the response to your request (JSON) is automatically unmarshalled to a Java object. 

If you are using maven, make sure you have the correct dependencies in your pom file:
    <dependency>
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-transports-http</artifactId>
       <version>${cxf.version}</version>
       <scope>provided</scope>
    </dependency>
   
    <dependency>
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-rs-extension-search</artifactId>
       <version>${cxf.version}</version>
       <scope>provided</scope>
    </dependency>
     
    <dependency>
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-rs-extension-providers</artifactId>
       <version>${cxf.version}</version>
       <scope>provided</scope>
    </dependency>
      
    <dependency>
    <groupId>com.fasterxml.jackson.jaxrs</groupId>
       <artifactId>jackson-jaxrs-json-provider</artifactId>
       <version>2.0.2</version>
    </dependency> 

Thursday, April 19, 2012

java XSLT processing with Saxon



Recently, I was looking for an efficient way to reduce the size of XML based clinical documents (CCD) that I am sending from a java REST API to mobile devices. These healthcare HL7 XML documents contain textual narrative blocks that are not used by the applications residing on the mobile devices.

On solution was to use Saxon, an open source XSLT processor in conjunction with a transformation style sheet to strip the Continuity of Care Documents of their narrative blocks.

In a CCD, each section under ClinicalDocument/component/structuredBody/component can have a text section that usually contains a narrative block similar to HTML content that can typically add 30% or more to the size of the CCD document:










































This has the advantage to avoid creating a full DOM representation, and is more robust and flexible than an event based sequential SAX processor.

The first step is to create a XSLT stylesheet that will transform (in my case strip the text sections) from the XML document.
In my case, since I wanted to remove all text sections, I was able to use an identity transform mechanism that I modified to strip the text sections (uses the hl7 namespace):

<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='2.0'
xmlns:hl7="urn:hl7-org:v3">

<xsl:output indent="no"/>
<xsl:strip-space elements="*"/>

<!-- identity template -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>

<!--  remove descriptive sections -->
<xsl:template match="hl7:text"/>  

</xsl:stylesheet>


Then I placed this file (I named it ccd_no_text_sections.xsl)  under the /src/main/resources folder.

To use this XSLT stylesheet with Saxon, you need to use one of the Saxon Java libaries.
If you using maven, for example, just add the dependencies to your pom file based on the version you want to use:
<dependency>
 <groupId>net.sf.saxon</groupId>
 <artifactId>saxon</artifactId>
 <version>9.0</version>
</dependency>

<dependency>
 <groupId>net.sf.saxon</groupId>
 <artifactId>saxon-dom</artifactId>
 <version>9.0</version>
</dependency>

or for the latest free version:

<dependency>
 <groupId>net.sf.saxon</groupId>
 <artifactId>Saxon-HE</artifactId>
 <version>9.4</version>
</dependency>

Then you need to create a transformer and call your style sheet for the transformation.
In my case, since I was planning other transformations, I decided to cash the XSLT transformer into a HashTable as follow:

import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

public class XSLTProcessor {

 private static final HashMap<String,Transformer> TRANSFORMER_CACHE = new HashMap<String,Transformer>();

 final static String CCD_NO_TEXT_SECTIONS = "/ccd_no_text_sections.xsl";
  
 private XSLTProcessor() {
   // no instantiation
 }

 private static Transformer getCCDTransformer() throws TransformerConfigurationException {

  Transformer transformer = TRANSFORMER_CACHE.get(CCD_NO_TEXT_SECTIONS);
  if (transformer == null) { 
   TransformerFactory tsf = TransformerFactory.newInstance();
         InputStream is = XSLTProcessor.class.getResourceAsStream(CCD_NO_TEXT_SECTIONS);
   transformer = tsf.newTransformer(new StreamSource(is));
   return transformer;
  }
  return transformer;
 }
 
 public static String stripTextSections(final String xmlString) throws TransformerConfigurationException,
        TransformerException, 
        TransformerFactoryConfigurationError {

        final StringReader xmlReader = new StringReader(xmlString);
        final StringWriter xmlWriter = new StringWriter();
        final Transformer ccdTransformer = getCCDTransformer();
        ccdTransformer.transform(new StreamSource(xmlReader),
            new StreamResult(xmlWriter));
        
        return xmlWriter.toString();
 }
}


In this way, you can easily add new transformers if needed and refer to them by their stylesheet name located under the resource folder.
In addition to this, the transformer is created only once and always available for a transformation.

The transformation can be called directly on the document as follow:

try {
    String new_ccd = XSLTProcessor.stripTextSections(ccd);
}
catch (TransformerConfigurationException e) {
    log.error("TransformerConfigurationException"+e);
}
catch (TransformerException e) {
    log.error("TransformerException"+e);
}
catch (TransformerFactoryConfigurationError e) {
    log.error("TransformerFactoryConfigurationError"+e);
}

Friday, February 24, 2012

Maven war plugin configuration section and web.xml




I am sure you have been in the following situation: you want to mavenize a web application project.

For this, you create a basic dynamic web application in Eclipse:



























You then import the application you want to build:






































After the import is done, you create a pom file.

You then update your eclipse configuration files via 'mvn clean eclipse:eclipse'

Finally you try to build your web application (war file) via 'mvn clean install'

However you get a bad surprise: First you are getting a BUILD ERROR:

 Error assembling WAR: webxml attribute is required (or pre-existing WEB-INF/web.xml if executing in update mode)

 ... and even though you seem to have created a war file, it only contains empty META-INF, WEB-INF and classes folders:


























The problem is that your web.xml file is not picked up by your maven build, because by default maven expects to find your web.xml inside src/main/resources


One option is to refactor your project and move your web.xml under src/main/resources/WEB-INF.

A better option is to modify your pom file and  add a maven war plugin configuration section to your build/plugins section.

In my case, I am specifying that my web.xml file is located under a WebContent folder, relative to the Pom file:
   
   <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-war-plugin</artifactId>
      <version>2.1.1</version>
      <!-- <configuration> section added to pick up the WEB-INF/web.xml inside WebContent -->
      <configuration>
         <webResources>
            <resource>
               <directory>WebContent</directory>
            </resource>
         </webResources>
      </configuration>
   </plugin>


When done, you just need to rebuild your web application (war file) via 'mvn clean install' and you should then obtain a  BUILD SUCCESSFUL with the war file content you were expecting!

Thursday, March 31, 2011

JUnit based integration testing with Simple JNDI



I regularly use TJWS  a light weight Java Web Server build as a servlet container to provide standard Web Server capabilities at building and testing time.

The main advantage is that I don't have to deploy my war file to my production server (e.g. JBoss) to test my Java Web application. My maven build runs complex integration JUnit tests immediately after building the war file with maven.

In my configuration however, I have to use JNDI (Java Naming and Directory Interface) to connect to a specific datasource (DB2 via JDBC) for some of  my tests.

I used Simple JNDI for this which also offer an easy and elegant way to configure data source access.

Here are the steps I follow to setup my JUnit tests using Simple JNDI:

    • Add dependencies in Maven 2 Pom file for Simple JNDI, java persistence and DB2 JNDI/JDBC:
        
        <dependency>
            <groupId>simple-jndi</groupId>
            <artifactId>simple-jndi</artifactId>
            <version>0.11.4.1</version>
            <scope>test</scope>
        </dependency>
    
        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>persistence-api</artifactId>
            <version>1.0</version>
            <scope>test</scope>
        </dependency>
      
        <dependency>
            <groupId>com.ibm.db2</groupId>
            <artifactId>db2jcc4</artifactId>
            <version>9.7.0.2</version>
            <scope>test</scope>
        </dependency>
        

    • Create a small Java class for the JNDI setup
         import javax.naming.InitialContext;
         import javax.sql.DataSource;
    
         public class JndiSetup { 
             /**
              * Setup the Data Source
              */
             public static void doSetup(String ds_name) {
                 try {
                     InitialContext ctxt = new InitialContext();
                     DataSource ds = (DataSource) ctxt.lookup("jdbc."+ds_name);
                     // rebind for alias if needed
                     ctxt.rebind("jdbc/"+ds_name, ds);
                 } catch (Exception ex) {
                     ex.printStackTrace();
                 }
             }
         }

    In more complex situations, you may have also to create an EntityManager and use an EntityManagerFactory.

    • In the JUnit java script code, setup your JNDI connection before running your tests:
        @BeforeClass
         public static void setUpClass() throws Exception {
              JndiSetup.doSetup("");
         }


    • Create a jndi.properties file in the "\src\test\resources" path in your project 
     
         java.naming.factory.initial=org.osjava.sj.SimpleContextFactory
         org.osjava.sj.root=target/test-classes/config
         org.osjava.jndi.delimiter=/
         org.osjava.sj.jndi.shared=true

    • Create a jdbc.properties file in the "\src\test\resources\config" path in your project (I am using an IBM DB2 data source). Create the config directory if it doesn't exist. The "config" name comes from org.osjava.sj.root parameter in jndi.properties file. If you want a different name, "foo", for the folder, make sure to update the "org.osjava.sj.root" property and create a "foo" folder in "\src\test\resources" path. Make sure the directory /src/test/resources is in the Java build path, and the output folder is set to target/test-classes
    
         <your-ds>.type=javax.sql.DataSource
         <your-ds>.driver=com.ibm.db2.jcc.DB2Driver
         <your-ds>.url=jdbc:db2://<your-database-host>:50000/<your-ds-or-ds-alias>
         <your-ds>.user=<your-db-login>
         <your-ds>.password=<your-db-password>

    With all of this you should be ready to test your integration using >mvn clean install.

    You may have also to do a >mvn eclipse:eclipse -DdownloadJavadocs=true as well if you are using Eclipse and your new dependencies and imports do not work properly.