In Flux, we have made improvements in recent versions to handle database or network failures and recover from such failures gracefully without needing to restart Flux. Sometimes, it would be nice to notify administrators about these failures and they can act upon them in case of an unscheduled outage. Flux is dependent on the database for maintaining job states and schedules, so fixing this problem is critical.

BoneCP, a popular JDBC Connection Pool has an interesting and useful feature which allows the connection pool to automatically recover from such DB outages and it replays the transactions when a healthy connection becomes available. This feature became available since its 0.6.5 release and I had tested this before and found this to be very useful when configured with Flux.

In BoneCP, we can implement a connection hook which gets triggered when database failures occur and it is easy to configure in Flux to use BoneCP as the datasource pool provider. In case of any database failure, you may want to send an email notification or initiate a SNMP trap so other downstream systems can be handled accordingly.

Here is a basic DatabaseShutdownHook would look like:

import com.jolbox.bonecp.ConnectionHandle;
import com.jolbox.bonecp.hooks.AbstractConnectionHook;
import com.jolbox.bonecp.hooks.AcquireFailConfig;

import java.util.Date;

public class DatabaseShutdownHook extends AbstractConnectionHook {
    @Override
    public boolean onConnectionException(ConnectionHandle connection, String state, Throwable t) {
        // handle notifications here: SNMP or SMTP
        System.out.println("Database down at " + new Date());
        return super.onConnectionException(connection, state, t);
    }

    @Override
    public boolean onAcquireFail(Throwable t, AcquireFailConfig acquireConfig) {
        // handle notifications here: SNMP or SMTP
        System.out.println("Failure to acquire connection at " + new Date() + ". Retry attempts remaining : " + acquireConfig.getAcquireRetryAttempts());
        return super.onAcquireFail(t, acquireConfig);
    }

}

Let us now see how to configure BoneCP as a Data source in Flux.

import com.jolbox.bonecp.BoneCPDataSource;
import flux.Configuration;
import flux.DatabaseType;
import flux.Engine;
import flux.Factory;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.sql.Connection;
import java.sql.SQLException;

public class FluxEngine {

    private static Context initialContext;

    static {
        try {
            System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");
            System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming");
            initialContext = new InitialContext();
            initializeDataSource();
        } catch (NamingException e) {
            // log exception
        } catch (SQLException e) {
            // log exception
        }
    }

    public static void initializeDataSource()  throws NamingException, SQLException {
        BoneCPDataSource ds = new BoneCPDataSource();
        ds.setJdbcUrl("jdbc:mysql://localhost:3306/flux710?relaxAutoCommit=true");
        ds.setUsername("flux");
        ds.setPassword("secret");
        ds.setMinConnectionsPerPartition(10);
        ds.setMaxConnectionsPerPartition(50);
        ds.setPartitionCount(1);
        ds.setConnectionHook(new DatabaseShutdownHook());// Required only if you need notifications.
        ds.setTransactionRecoveryEnabled(true);// Important: This should be enabled
        ds.setAcquireRetryAttempts(10);//default is 5
        ds.setAcquireRetryDelay(10000);// default is 7 secs
        ds.setReleaseHelperThreads(5);

        Connection con = ds.getConnection();
        if (con != null) {
            initialContext.rebind("FluxDataSource", ds);
            con.close();
        }
        System.out.println("DataSource configured.");
    }

    public static void main(String[] args) throws Exception {
        Factory f = Factory.makeInstance();
        Configuration c = f.makeConfiguration();
        c.setDatabaseType(DatabaseType.MYSQL);
        c.setDataSource("FluxDataSource");
        Engine engine = f.makeEngine(c);
        engine.start();
        System.out.println("Engine started.");
    }
}

Data sources should be made available via JNDI for Flux to use them. So, in this example I used Tomcat JNDI support to expose the BoneCP datasource via JNDI. There are also other ways to expose this via JNDI when running Flux as a standalone server. Tomcat JNDI was easy to configure though as you can see from the code above. The BoneCP data source should be configured for transaction recovery and you can set the number of recovery attempts and retry delay.

I have created a simple flow chart which has a Timer Trigger followed by a Java Action. The timer is configured to fire every 15 seconds for 5 times as shown below.

process_data.png

Here is a sample output of running this job in Flux configured with BoneCP and MySQL database. I shutdown MySQL server when this job was running and you can see the BoneCP recovery attempts and after a while I brought back the MySQL server and BoneCP successfully recovered. Now, you can see Flux execute the last occurrence of this job successfully.

DataSource configured.
Engine started.
Done processing data

Done processing data

Done processing data

Done processing data

Database down at Sun Oct 10 12:18:12 MDT 2010
Oct 10, 2010 12:18:12 PM com.jolbox.bonecp.ConnectionHandle markPossiblyBroken
SEVERE: Database access problem. Killing off all remaining connections in the connection pool. SQL State = 08007
Oct 10, 2010 12:18:12 PM com.jolbox.bonecp.MemorizeTransactionProxy invoke
SEVERE: Connection failed. Attempting to recover transaction on Thread #70
Oct 10, 2010 12:18:14 PM com.jolbox.bonecp.hooks.AbstractConnectionHook onAcquireFail
SEVERE: Failed to acquire connection Sleeping for 10000ms and trying again. Attempts left: 10. Exception: java.net.ConnectException: Connection refused: connect
Failure to acquire connection at Sun Oct 10 12:18:14 MDT 2010. Retry attempts remaining : 10
Oct 10, 2010 12:18:26 PM com.jolbox.bonecp.hooks.AbstractConnectionHook onAcquireFail
SEVERE: Failed to acquire connection Sleeping for 10000ms and trying again. Attempts left: 9. Exception: java.net.ConnectException: Connection refused: connect
Failure to acquire connection at Sun Oct 10 12:18:26 MDT 2010. Retry attempts remaining : 9
Oct 10, 2010 12:18:38 PM com.jolbox.bonecp.hooks.AbstractConnectionHook onAcquireFail
SEVERE: Failed to acquire connection Sleeping for 10000ms and trying again. Attempts left: 8. Exception: java.net.ConnectException: Connection refused: connect
Failure to acquire connection at Sun Oct 10 12:18:38 MDT 2010. Retry attempts remaining : 8
Oct 10, 2010 12:18:48 PM com.jolbox.bonecp.MemorizeTransactionProxy invoke
SEVERE: Recovery succeeded on Thread #70
Done processing data

The following BoneCP dependencies are required in the classpath:
bonecp-0.7.0.jar
guava-r07.jar
slf4j-api-1.6.1.jar
slf4j-jdk14-1.6.1.jar (Note: You can use any logger bindings supported by slf4j. Using JDK logger for simplicity and one less jar.)

To configure Tomcat JNDI, you need to have these jars in classpath:
catalina.jar
tomcat-juli.jar

Let me know if you have any trouble setting up this in Flux.

(Update: 10/13): Updated to reference the latest stable 0.7.0 release which now uses Google guava instead of the retired Google collections library and fixed slf4j dependency requirement.

Possibly Related Posts:


Try-with-resources (originally known as Automatic Resource Management) is one of the Project Coin proposals that made its way into recent JDK 7 builds. Traditionally, developers had to manually terminate any resources (Files, Database connections, etc) they use in their applications and sometimes it was painful to keep track of those things and failing to do so may have serious problems such as resource leaks which could potentially lead to application failures that are hard to debug and triage. The burden of managing resources is no more a developer’s headache as this will be natively supported in Java 7.

C# has “using” blocks and C++ destructors served a similar purpose. This is a more sought after language feature for years and Joshua Bloch brings this to real for Java developers with some syntax sugaring. While this construct looks alien to Java, I believe this is something we have to accept and move forward as this solves common programming errors. IDEs can fill this space to support intelligent code completion for ARM constructs and make it easy for developer adoption. The other disadvantage outlined in the proposal is increased coupling between the language specification and libraries. To support this feature, a class must implement a designated interface AutoCloseable to make it eligible for automatic resource management.

Let us look at the example used in the ARM proposal, copying a file involving two resources.

    public void copy(String src, String dest) throws IOException {
        InputStream in = new FileInputStream(src);
        try {
            OutputStream out = new FileOutputStream(dest);
            try {
                byte[] buf = new byte[8192];
                int n;
                while ((n = in.read(buf)) >= 0)
                    out.write(buf, 0, n);
            } finally {
                out.close();
            }
        } finally {
            in.close();
        }
    }

With the new try-with-resources construct, we should be able to rewrite the above code with much simplicity:

    public void copy(String src, String dest) throws IOException {
        try(InputStream in = new FileInputStream(src);
            OutputStream out = new FileOutputStream(dest)){
            byte[] buf = new byte[8192];
            int n;
            while ((n = in.read(buf)) >= 0)
                out.write(buf, 0, n);
        }
    }

The bloated code we use these days will become more crisp with fewer lines of code, while continuing to maintain readability.

Java APIs that involve dealing with resources are mostly retrofitted to support this new AutoCloseable interface. This feature brings heap of benefits to the JDBC world where this may prove very useful when managing database connections and its subsidiaries.

Here is the traditional way of programming in JDBC where the user has to manage JDBC resources such as ResultSet, Statement and Connection.

        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            conn = DriverManager.getConnection("jdbc:h2:mem:test", "sa", "");
            stmt = conn.createStatement();
            rs = stmt.executeQuery("SELECT * FROM INFORMATION_SCHEMA.USERS");
            while (rs.next()) {
                System.out.println(rs.getString(1));
            }
        } catch (SQLException e) {
            // handle exception
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                }
                rs = null;
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                }
                stmt = null;
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                }
                conn = null;
            }

        }

You guessed it right, there is so much boilerplate code that is involved here. Here is the same code with our try-with-resources construct.

        try(Connection conn = DriverManager.getConnection("jdbc:h2:mem:test", "sa", "");
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT * FROM INFORMATION_SCHEMA.USERS")) {// no trailing semicolon in the last line of the block containing automatic resource definition
            while (rs.next()) {
                System.out.println(rs.getString(1));
            }
        } catch (SQLException e) {
            // handle exception
        }

Wow, it is compact and powerful. JDBC support for the new try-with-resources construct will be part of JDBC 4.1 specification and the implementation is available in the recent JDK 7 build 112.

In these try-with-resources examples, an exception thrown during the lifetime of a try-with-resources statement receives priority over an exception thrown by an automatically generated close invocation. The proposal addresses automatic retention of those suppressed exceptions which are associated with the primary exception thrown during the try-with-resources statement.

The following methods are added to java.lang.Throwable to support extraction of these suppressed exceptions.

    public synchronized void addSuppressedException(Throwable exception);

    public synchronized Throwable[] getSuppressedExceptions();

You may want to go through the recent JavaOne presentation which details Project Coin features that are included in Java 7, slated for release in mid 2011.

Do you think Project Coin will become a crown jewel of Java 7, since Lambda expressions and Project Jigsaw are no longer the main contenders? In the coming days, I will be exploring many other language features that are included in Java 7 and help you decide the crown jewel of Java 7.

Keep watching this space for more Java 7 delicacies 🙂

Possibly Related Posts:


JAXB is the defacto OXM binding framework for the Java platform which performs marshalling (serializing Java to XML) and unmarshalling (deserializing XML to Java) using the standard Java APIs. I must admit that JAXB is a smart addition to the Java Web services technologies stack. It reminds me of days where I used to write custom serializers/deserializers using the first generation Web services stack Axis. It used to scare away developers using complex types in their applications because of its complexity. I do agree data binding frameworks has its limitations, but no technology is a “silver-bullet”. When it comes to programming with Web services (whether JAXWS or JAXRS), JAXB is a first-class citizen in every Web services frameworks (Axis2, CXF, Jersey, Metro, RESTEasy, Wink) out there for Java developers.

IDEs have become very smart these days and they provide nice tooling around these technologies, which makes development of applications based on web services, a child’s play. XML schemas have become the natural choice for data modeling, due to its wide adoption in enterprise application integration. While, JAXB fits the bill nicely when programming in Java, it sometimes can be verbose primarily due to the heavy use of its annotations and requiring changes to source code. There may be cases where users would not have access to sources and annotating them is not an option for them. For others, it does not make sense to annotate just for the sake of mapping objects from one format to other. There is good news for these users that do want to use JAXB with out any intrusion to their code.

JAXB framework provides customization options that makes it possible to use it seamlessly without modifying source code and abstracting out those metadata in configuration files.

I am going to discuss about two popular options that helps achieve this goal.
1. MOXy from EclipseLink.
2. JAXBIntroductions from JBoss ESB.

While both these projects specifically address the concern of using annotations on your application model, EclipseLink MOXy provides advanced customizations on marshalling your domain objects. Let us build a simple Jersey application using these options for our vanilla domain model. You guessed it right, its time to dive into our Maven POM.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <name>MOXy/JAXBIntro</name>
    <groupId>jersey-moxy-jaxbintro</groupId>
    <artifactId>jersey-moxy-jaxbintro</artifactId>
    <version>1.0</version>

    <dependencies>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>eclipselink</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>jboss.jaxbintros</groupId>
            <artifactId>jboss-jaxb-intros</artifactId>
            <version>1.0.2.GA</version>
        </dependency>        
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>1.3</version>
        </dependency>
        <dependency>
            <groupId>com.sun.grizzly</groupId>
            <artifactId>grizzly-servlet-webserver</artifactId>
            <version>1.9.18-i</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.1</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>EclipseLink Repo</id>
            <url>http://www.eclipse.org/downloads/download.php?r=1&amp;nf=1&amp;file=/rt/eclipselink/maven.repo</url>
        </repository>
        <repository>
            <id>maven2-repository.dev.java.net</id>
            <name>Java.net Repository for Maven</name>
            <url>http://download.java.net/maven/2/</url>
            <layout>default</layout>
        </repository>
        <repository>
            <id>jboss-public-repository-group</id>
            <name>JBoss Public Maven Repository Group</name>
            <url>https://repository.jboss.org/nexus/content/groups/public-jboss/</url>
            <layout>default</layout>
            <releases>
                <enabled>true</enabled>
                <updatePolicy>never</updatePolicy>
            </releases>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>never</updatePolicy>
            </snapshots>
        </repository>
    </repositories>
</project>

To keep this example simple, I would like to reuse the entities such as Customer, Address and PhoneNumber used in MOXy examples. They are simple POJOs and do not carry any metadata on them. Here is the Customer POJO (others are omitted for brevity):

public class Customer {

    private String name;
    private Address address;
    private List<PhoneNumber> phoneNumber;

    public Customer() {
        phoneNumber = new ArrayList<PhoneNumber>();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public List<PhoneNumber> getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(List<PhoneNumber> phoneNumber) {
        this.phoneNumber = phoneNumber;
    }
}

The MOXy configuration file(eclipselink-oxm.xml) which defines the metadata for these entities is shown below.

<?xml version="1.0"?>
<xml-bindings
        xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
        version="2.1">
    <java-types>
        <java-type name="com.mycorp.model.Customer">
            <xml-root-element/>
            <xml-type prop-order="name address phoneNumber"/>
            <java-attributes>
                <xml-element java-attribute="name" xml-path="personal-info/name/text()"/>
                <xml-element java-attribute="address" xml-path="contact-info/address"/>
                <xml-element java-attribute="phoneNumber" xml-path="contact-info/phone-number"/>
            </java-attributes>
        </java-type>
        <java-type name="com.mycorp.model.PhoneNumber">
            <xml-root-element/>
            <java-attributes>
                <xml-attribute java-attribute="type"/>
                <xml-value java-attribute="value"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

You may want to reference how these metadata translates to Java annotations as detailed in this wiki example. As you may notice, this configuration is fairly simple to understand and provides more flexibility in terms of how your marshalled XML data may look like.

So far, we have seen this from the MOXy perspective and now let us see how this would be used in a Jersey application. For this, we need to implement a ContextResolver which can be used to instantiate and inject a custom JAXBContext onto the message body writer for our domain model. Here is our implementation of a ContextResolver that uses EclipseLink API JAXBContextFactory to create a JAXBContext which will be used for our marshalling business in Jersey. The configuration file (eclipselink-oxm.xml) dictates how the XML is generated by this marshaller.

import com.mycorp.model.Customer;
import org.eclipse.persistence.jaxb.JAXBContextFactory;

import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import java.util.*;

@Provider
public final class JAXBContextResolverForMOXy implements ContextResolver<JAXBContext> {

    private final JAXBContext context;
    private final Set<Class> types;
    private final Class[] cTypes = {Customer.class};

    public JAXBContextResolverForMOXy() throws Exception {
        this.types = new HashSet(Arrays.asList(cTypes));
        Map<String, Source> metadataSourceMap = new HashMap<String, Source>();
        metadataSourceMap.put("com.mycorp.model", new StreamSource(this.getClass().getResourceAsStream("/eclipselink-oxm.xml")));
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, metadataSourceMap);
        this.context = JAXBContextFactory.createContext(cTypes, properties);
    }

    public JAXBContext getContext(Class<?> objectType) {
        return (types.contains(objectType)) ? context : null;
    }
}

Now, we have the JAXBContextResolver that can be injected to our MessageBodyWriter to perform marshalling. The Customer MessageBodyWriter is the key which wires Customer objects to an externalized JAXB configuration using the custom marshaller injected by Jersey runtime. Here is the trivial implementation of our Customer MBW.

@Provider
@Produces("application/xml")
public class CustomerMessageBodyWriter implements MessageBodyWriter<Customer> {

    @Context
    ContextResolver<JAXBContext> contextResolver;

    @Override
    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return Customer.class.isAssignableFrom(type);
    }

    @Override
    public long getSize(Customer customer, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return -1;
    }

    @Override
    public void writeTo(Customer customer, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
        JAXBContext context = contextResolver.getContext(type);
        try {
            context.createMarshaller().marshal(customer, entityStream);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }
}

Now, it is time to wire all these parts together to see the magic. Here is our simple CustomerResource that just returns a Customer representation.

@Path("customers")
@Produces("application/xml")
public class CustomerResource {

    @GET
    public Customer getCustomer() {
        Customer customer = new Customer();
        customer.setName("Jane Doe");

        Address address = new Address();
        address.setStreet("123 Any Street");
        address.setCity("My Town");
        customer.setAddress(address);

        PhoneNumber workPhoneNumber = new PhoneNumber();
        workPhoneNumber.setType("work");
        workPhoneNumber.setValue("613-555-1111");
        customer.getPhoneNumber().add(workPhoneNumber);

        PhoneNumber cellPhoneNumber = new PhoneNumber();
        cellPhoneNumber.setType("cell");
        cellPhoneNumber.setValue("613-555-2222");
        customer.getPhoneNumber().add(cellPhoneNumber);

        return customer;
    }
}

Accessing the URL, http://localhost:9998/jaxb/customers, produces the following XML:

<?xml version="1.0" encoding="UTF-8"?>
<customer>
    <personal-info>
        <name>Jane Doe</name>
    </personal-info>
    <contact-info>
        <address>
            <city>My Town</city>
            <street>123 Any Street</street>
        </address>
        <phone-number type="work">613-555-1111</phone-number>
        <phone-number type="cell">613-555-2222</phone-number>
    </contact-info>
</customer>

Let us do a similar exercise using JAXBIntroductions which follows a similar pattern. The configuration file(intro-config.xml) of JAXBIntros is shown below.

<?xml version = "1.0" encoding = "UTF-8"?>
<jaxb-intros xmlns="http://www.jboss.org/xsd/jaxb/intros">
    <Class name="com.mycorp.model.Customer">
        <XmlAccessorType value="FIELD"/>
        <XmlType propOrder="name,address,phoneNumber"/>
        <XmlRootElement  name="customer"/>      

        <Field name="name">
            <XmlElement name="name"/>
        </Field>
        <Field name="address">
            <XmlElement name="address"/>
        </Field>
        <Field name="phoneNumber">
            <XmlElementWrapper name="phoneNumbers"/>
        </Field>
    </Class>
</jaxb-intros>

We have to write a new ContextResolver that uses JAXBIntroductions APIs to introduce the JAXB annotations for a given JAXBContext via a RuntimeInlineAnnotationReader implementation.

import com.mycorp.model.Customer;
import com.sun.xml.bind.api.JAXBRIContext;
import org.jboss.jaxb.intros.IntroductionsAnnotationReader;
import org.jboss.jaxb.intros.IntroductionsConfigParser;
import org.jboss.jaxb.intros.configmodel.JaxbIntros;

import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;
import java.util.*;

@Provider
public class JAXBContextResolverForJAXBIntroductions implements ContextResolver<JAXBContext> {

    private final JAXBContext context;
    private final Set<Class> types;
    private final Class[] cTypes = {Customer.class};

    public JAXBContextResolverForJAXBIntroductions() throws Exception {
        this.types = new HashSet(Arrays.asList(cTypes));
        JaxbIntros config = IntroductionsConfigParser.parseConfig(this.getClass().getResourceAsStream("/intro-config.xml"));
        IntroductionsAnnotationReader reader = new IntroductionsAnnotationReader(config);
        Map<String, Object> jaxbConfig = new HashMap<String, Object>();
        jaxbConfig.put(JAXBRIContext.ANNOTATION_READER, reader);
        this.context = JAXBContext.newInstance(cTypes, jaxbConfig);
    }

    public JAXBContext getContext(Class<?> objectType) {
        return (types.contains(objectType)) ? context : null;
    }
}

Accessing the URL, http://localhost:9998/jaxb/customers, produces the following XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
    <name>Jane Doe</name>
    <address>
        <city>My Town</city>
        <street>123 Any Street</street>
    </address>
    <phoneNumbers>
        <phoneNumber>
            <type>work</type>
            <value>613-555-1111</value>
        </phoneNumber>
        <phoneNumber>
            <type>cell</type>
            <value>613-555-2222</value>
        </phoneNumber>
    </phoneNumbers>
</customer>

Hopefully, these examples demonstrate the benefits of using OXM tools to simplify generating XML using custom JAXB marshallers in Jersey or any other JAX-RS provider, without requiring JAXB annotations on their domain model. While, both these options are easier to implement, you may want to choose the one which fits your needs. For most cases, JAXBIntroductions should suffice as it is lightweight. If you are looking for converting JPA entities to/from XML (via JAXB), then I would prefer MOXy.

Download the project sources here. Feedback/suggestions are always welcome 🙂

Update (8/17) : Fixed the output produced from JAXBIntroductions, as it was a copy/paste error in the original post. Now, you can notice the difference between the marshalled XML in both cases. Thanks Blaise for pointing this out and providing reference to your blog post which explains how MOXy uses XPath mapping extension to add in the “personal-info” and “contact-info” grouping elements to our marshalled XML.

Possibly Related Posts:


It is quite possible many developers have run into this problem with Jersey, not really a problem, but limitations of a programming language. I remember from school days where C++ Templates had quite a few reference books and it always kept me away from using STL containers 🙂

In Java, we have Generics since 1.5 which looks lot like C++ Templates, but they are not the same. I am not going to cover the details here, just google it. But, Generics have grown in such complexity that it has dedicated 500+ pages FAQ written and maintained by Angelika Langer for years (JLS 3rd edition is only 684 pages).

Long story short: Generics provides compile time type safety and thus eliminating the need for casts. It is achieved through a compile time phenomenon called type erasure. The Generics FAQ explains everything in detail and it is the Java Generics Bible at least for me.

There are cases when we need to return parameterized types from a JAXRS resource method in the Response. Due to type erasure, it requires special handling in Jersey runtime to determine the generic type that is required to select a suitable MessageBodyWriter.

There are couple options available for JAX-RS developers using Jersey and I am going discuss each one of them in detail.

Let us consider a simple domain model, Employee.

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "employee")
public class EmployeeBean {
    private Long id;
    private String firstName;
    private String lastName;

    public EmployeeBean() {
        // required for JAXB
    }

    public EmployeeBean(Long id, String firstName, String lastName) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

The employee resource shows an example implementation.

@Path("/employees")
public class EmployeeResource {

    @GET
    public Collection<EmployeeBean> getEmployees() {
        EmployeeBean emp = new EmployeeBean(1L, "John", "Doe");
        return Collections.singletonList(emp);
    }
}

In this case, we return the Collection of EmployeeBean from the resource method. The following XML is produced on accessing this resource at http://localhost:9998/employees.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employeeBeans>
    <employee>
        <firstName>John</firstName>
        <id>1</id>
        <lastName>Doe</lastName>
    </employee>
</employeeBeans>

I would expect to see the list of employees inside <employees> tag instead of <employeeBeans> tag. Hmm, it requires some tweaks to produce that format. So, lets write Employees POJO which embeds the Collection.

@XmlRootElement
public class Employees {
    private List<EmployeeBean> employee;

    public Employees(List<EmployeeBean> employee) {
        this.employee = employee;
    }

    public Employees() {
        // required for JAXB
    }

    public List<EmployeeBean> getEmployee() {
        return employee;
    }

    public void setEmployee(List<EmployeeBean> employee) {
        this.employee = employee;
    }
}

Let us add couple methods to the EmployeeResource using Customers POJO that produces a more relevant XML.

    @GET
    @Path("test1")
    public Employees getEmployees1() {
        EmployeeBean emp = new EmployeeBean(1L, "John", "Doe");
        Employees employees = new Employees(Collections.singletonList(emp));
        return employees;
    }

    @GET
    @Path("test2")
    public Response getEmployees2() {
        EmployeeBean emp = new EmployeeBean(1L, "John", "Doe");
        Employees employees = new Employees(Collections.singletonList(emp));
        return Response.ok(employees).build();
    }

Now, accessing http://localhost:9998/employees/test1 or http://localhost:9998/employees/test2 should produce the following XML.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employees>
    <employee>
        <firstName>John</firstName>
        <id>1</id>
        <lastName>Doe</lastName>
    </employee>
</employees>

But, do we need this silly logic to produce this output? Not anymore, this has been improved in Jersey 1.2 release. Enabling FEATURE_XMLROOTELEMENT_PROCESSING feature in resource configuration should produce this format out of the box. So, accessing http://localhost:9998/employees/test1 should produce this format of XML. This property is disabled by default.

Now, lets dive into our actual problem of type erasure in case of a parameterized type returned in the JAX-RS Response. I have added another method to our EmployeeResource.

    @GET
    @Path("test3")
    @Produces(MediaType.APPLICATION_XML)
    public Response getEmployees3() {
        EmployeeBean emp = new EmployeeBean(1L, "John", "Doe");
        List<EmployeeBean> list = new ArrayList<EmployeeBean>();
        list.add(emp);
        return Response.ok(list).build();
    }

Now, accessing this method at http://localhost:9998/employees/test3 should spit the following exception. I believe this exception trace is familiar to most Jersey/JAX-RS users.

SEVERE: A message body writer for Java class java.util.ArrayList, and Java type class java.util.ArrayList, and MIME media type application/xml was not found
Jul 24, 2010 11:58:55 PM com.sun.jersey.spi.container.ContainerResponse write
SEVERE: The registered message body writers compatible with the MIME media type are:
application/xml ->
  com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$App
  com.sun.jersey.core.impl.provider.entity.DocumentProvider
  com.sun.jersey.core.impl.provider.entity.SourceProvider$SourceWriter
  com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$App
  com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$App
*/* ->
  com.sun.jersey.core.impl.provider.entity.FormProvider
  com.sun.jersey.server.impl.template.ViewableMessageBodyWriter
  com.sun.jersey.core.impl.provider.entity.StringProvider
  com.sun.jersey.core.impl.provider.entity.ByteArrayProvider
  com.sun.jersey.core.impl.provider.entity.FileProvider
  com.sun.jersey.core.impl.provider.entity.InputStreamProvider
  com.sun.jersey.core.impl.provider.entity.DataSourceProvider
  com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$General
  com.sun.jersey.core.impl.provider.entity.ReaderProvider
  com.sun.jersey.core.impl.provider.entity.DocumentProvider
  com.sun.jersey.core.impl.provider.entity.StreamingOutputProvider
  com.sun.jersey.core.impl.provider.entity.SourceProvider$SourceWriter
  com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$General
  com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$General

Jul 24, 2010 11:58:55 PM com.sun.jersey.spi.container.ContainerResponse traceException
SEVERE: Mapped exception to response: 500 (Internal Server Error)
javax.ws.rs.WebApplicationException

To fix this, we need to somehow tell the JAX-RS runtime the type of the response entity, in this case a Collection of Employees. JAX-RS API GenericEntity comes to the rescue. GenericEntity can be used to represent a response entity of a generic type. The EmployeeResource method is updated to use the GenericEntity class when returning a Collection type.

    @GET
    @Path("test4")
    @Produces(MediaType.APPLICATION_XML)
    public Response getEmployees4() {
        EmployeeBean emp = new EmployeeBean(1L, "John", "Doe");
        List<EmployeeBean> list = new ArrayList<EmployeeBean>();
        list.add(emp);
        GenericEntity entity = new GenericEntity<List<EmployeeBean>>(list) {};
        return Response.ok(entity).build();
    }

Accessing http://localhost:9998/employees/test4 should produce the desired output.

In addition to this approach, Jersey 1.2 introduced a new API JResponse to support this better. JResponse is a type safe alternative to Response that preserves the type information of response entity thus it is not necessary to utilize GenericEntity.

The updated Employee resource using JResponse is shown below.

    @GET
    @Path("test5")
    @Produces(MediaType.APPLICATION_XML)
    public JResponse<List<EmployeeBean>> getEmployees5() {
        EmployeeBean emp = new EmployeeBean(1L, "John", "Doe");
        List<EmployeeBean> list = new ArrayList<EmployeeBean>();
        list.add(emp);
        return JResponse.ok(list).build();
    }

Accessing http://localhost:9998/employees/test5 should produce the desired output.

Both these approaches are easy to implement. The major difference is GenericEntity is a JAX-RS API while JResponse is a Jersey API, which may not work with other JAX-RS implementations and thus not portable. If you are just using Jersey, then JResponse is the preferred way as it is type safe and provides all capabilities of the Response.

Here is the Server code that uses Grizzly (provided for completion) :

import com.sun.grizzly.http.SelectorThread;
import com.sun.jersey.api.container.grizzly.GrizzlyWebContainerFactory;
import com.sun.jersey.core.util.FeaturesAndProperties;

import javax.ws.rs.core.UriBuilder;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;

public class Main {

    private static int getPort(int defaultPort) {
        String port = System.getenv("JERSEY_HTTP_PORT");
        if (null != port) {
            try {
                return Integer.parseInt(port);
            } catch (NumberFormatException e) {
            }
        }
        return defaultPort;
    }

    private static URI getBaseURI() {
        return UriBuilder.fromUri("http://localhost/").port(getPort(9998)).build();
    }

    public static final URI BASE_URI = getBaseURI();

    protected static SelectorThread startServer() throws IOException {
        final Map<String, String> initParams = new HashMap<String, String>();

        initParams.put("com.sun.jersey.config.property.packages", "com.employee.resources");
        initParams.put(FeaturesAndProperties.FEATURE_XMLROOTELEMENT_PROCESSING, "true");

        System.out.println("Starting grizzly...");
        SelectorThread threadSelector = GrizzlyWebContainerFactory.create(BASE_URI, initParams);
        return threadSelector;
    }

    public static void main(String[] args) throws IOException {
        SelectorThread threadSelector = startServer();
        System.out.println(String.format("Jersey app started with WADL available at "
                + "%sapplication.wadl\nTry out %shelloworld\nHit enter to stop it...",
                BASE_URI, BASE_URI));
        System.in.read();
        threadSelector.stopEndpoint();
    }
}

I hope this clarifies some of the underlying behavior of handling parameterized types in JAX-RS applications.

Possibly Related Posts:


I recently came across this interesting question on Job Scheduling in Java in the widely popular experts-exchange website. Unfortunately, you require subscription to see “expert” answers, unlike Stack Overflow. Here is my take on this FAQ:

1) Is it possible to use Sun’s own java.util.TimerTask for my complex report scheduling?

Timer facility has limited capabilities when compared to JDK 5 concurrency utilities. This is best explained in Chapter 6 (6.2.5 Delayed and periodic tasks) of Java Concurrency In Practice by Brian Goetz, the best Java concurrency book on the planet. Fortunately, you can access this sample chapter Task Execution.

Here is the gist from the book (for the impatience):

a) A Timer creates only a single thread for executing timer tasks. If a timer task takes too long to run, the timing accuracy of other TimerTasks can suffer.

b) Another problem with Timer is that it behaves poorly if a TimerTask throws an unchecked exception. The Timer thread doesn’t catch the exception, so an unchecked exception thrown from a TimerTask terminates the timer thread. Timer also doesn’t resurrect the thread in this situation; instead, it erroneously assumes the entire Timer was cancelled. In this case, TimerTasks that are already scheduled but not yet executed are never run, and new tasks cannot be scheduled.

2) What are the valid/strong reasons/limitations of java.util.TimerTask compared to other job scheduler frameworks? So that I myself have a strong belief/reason before choosing a third-party job scheduler framework.

I do not believe Timer facility can be compared with other job scheduling frameworks as it does not provide features that are critical in a typical job scheduling environment. Here is what Flux offers (this is only a subset of the total feature set) :

a) Time and Event based scheduling.
b) Agent/Agentless scheduling.
c) Built-in File monitoring or transfer (FTP, FTP over SSL, SFTP, UNC hosts).
d) Integration with JEE (JMS, EJB, Mail) and Web Services (SOAP, REST).
e) Built-in Error Handling and supports email notifications.
f) Logging and Audit Trail.
g) Web-based Designer, Swing-based Designer.
h) Operations Console (Realtime job monitoring, management and reporting).
i) Built-in Security using JAAS and supports integration with LDAP.
j) Automatic Clustering, Failover, and Load Balancing of Jobs.

For complete feature set, please refer the Flux manual.

3) There are a maximum of 100-200 Users in my application. In case, Users have scheduled reports in such a way at one time there are 100 report requests in the queue. How does the job scheduler framework OR java.util.TimerTask handle such scenarios? Do we have control over this?

In Flux, we have the concept of concurrency throttles which allows users to control how many jobs that can be executed on the Flux engine at any given instant. You can define a concurrency throttle that governs a single Flux instance, or you can define a concurrency throttle that governs all jobs in all Flux instances on your cluster. These coarse-grained concurrency throttles control the parallel execution of large numbers of jobs in one step.

You can also define fine-grained concurrency throttles. For each branch in your job tree, you can define a unique concurrency throttle that governs only the jobs in that branch. More on this can be found in our manual.

4) At any time, Users are allowed to change their report schedules. Does the job scheduler framework support this?

In Flux, this can be achieved either using the Operations Console which allows users to reschedule their job schedule using the web interface or using the Java API programatically. Operations Console provides users advanced monitoring capabilities and it allows users to view jobs as well as pause, resume, remove, interrupt, and expedite them.

5) Obviously, to run a report there are report inputs, that has to be passed to each report schedule. Do we have the flexibility/option in passing parameters to the job scheduler framework?

This is a very common requirement for any job scheduler and Flux supports it using the concept of variable managers (Java API) which allows users to pass parameters to their jobs. Flux also has a neat feature called variable substitution, which can be quite powerful when designing jobs and externalizing certain server specific information (such as host names, credentials, etc) from the job.

6) Which is the best way? Integrating job scheduler framework with web application or running it as a standalone?

Flux supports both the approaches. Quite honestly, it depends on how you would want to leverage the scheduling capabilities within your application. It is a common usecase to embed Flux within applications as Flux provides extensive Java APIs.

It takes less than 5 minutes to setup Flux up and running with an in-memory database. Can you believe that? Give it a try yourself. Let me know what you think.

Possibly Related Posts:


JAX-RS runtime allows applications to supply entity providers which maps services between representations (via @Produces and @Consumes) and their Java types. The entity provider interfaces MessageBodyReader and MessageBodyWriter defines the contract that supports the conversion of a stream to a Java type and vice versa.

Lets write a simple JAXRS provider for handling a SOAPMessage on the client-side.

import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import javax.xml.soap.*;
import javax.xml.transform.stream.StreamSource;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

@Provider
@Consumes(MediaType.TEXT_XML)
@Produces(MediaType.TEXT_XML)
public class SoapProvider implements MessageBodyWriter<SOAPMessage>, MessageBodyReader<SOAPMessage> {
    public boolean isWriteable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
        return SOAPMessage.class.isAssignableFrom(aClass);
    }

    public SOAPMessage readFrom(Class<SOAPMessage> soapEnvelopeClass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> stringStringMultivaluedMap, InputStream inputStream) throws IOException, WebApplicationException {
        try {
            MessageFactory messageFactory = MessageFactory.newInstance();
            StreamSource messageSource = new StreamSource(inputStream);
            SOAPMessage message = messageFactory.createMessage();
            SOAPPart soapPart = message.getSOAPPart();
            soapPart.setContent(messageSource);
            return message;
        } catch (SOAPException e) {
            e.printStackTrace();
        }
        return null;
    }

    public long getSize(SOAPMessage soapMessage, Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
        return -1;
    }

    public void writeTo(SOAPMessage soapMessage, Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> stringObjectMultivaluedMap, OutputStream outputStream) throws IOException, WebApplicationException {
        try {
            soapMessage.writeTo(outputStream);
        } catch (SOAPException e) {
            e.printStackTrace();
        }
    }

    public boolean isReadable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
        return aClass.isAssignableFrom(SOAPMessage.class);
    }
}

I used Jersey client to invoke the Weather Web Service from CDYNE. You can use any wsdl2java tool (I used CXF) to generate the types from the WSDL. Jersey would use the registered provider to map the SOAPMessage to the request and response. And finally, we bind the SOAPBody to the WSDL type using JAXB.

import com.cdyne.ws.weatherws.GetCityWeatherByZIPResponse;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.client.filter.LoggingFilter;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.soap.*;

public class RESTyClient {
    public static void main(String[] args) throws Exception {
        ClientConfig config = new DefaultClientConfig();
        config.getClasses().add(SoapProvider.class);
        Client c = Client.create(config);
        c.addFilter(new LoggingFilter());

        MessageFactory messageFactory = MessageFactory.newInstance();
        SOAPMessage message = messageFactory.createMessage();
        SOAPPart soapPart = message.getSOAPPart();
        SOAPEnvelope envelope = soapPart.getEnvelope();
        SOAPBody body = envelope.getBody();
        SOAPElement bodyElement = body.addChildElement(envelope.createName("GetCityWeatherByZIP", "", "http://ws.cdyne.com/WeatherWS/"));
        bodyElement.addChildElement("ZIP").addTextNode("59102");
        message.saveChanges();

        WebResource service = c.resource("http://ws.cdyne.com/WeatherWS/Weather.asmx");

        // POST the request
        ClientResponse cr = service.header("SOAPAction", "\"http://ws.cdyne.com/WeatherWS/GetCityWeatherByZIP\"").post(ClientResponse.class, message);
        message = cr.getEntity(SOAPMessage.class);

        JAXBContext ctx = JAXBContext.newInstance(GetCityWeatherByZIPResponse.class);
        Unmarshaller um = ctx.createUnmarshaller();
        GetCityWeatherByZIPResponse response = (um.unmarshal(message.getSOAPPart().getEnvelope().getBody().extractContentAsDocument(), GetCityWeatherByZIPResponse.class)).getValue();
        System.out.println("City : " + response.getGetCityWeatherByZIPResult().getCity());
        System.out.println("Temperature : " + response.getGetCityWeatherByZIPResult().getTemperature());
    }
}

Here is a sample output from the test.

Dec 3, 2009 10:02:04 PM com.sun.jersey.api.client.filter.LoggingFilter log
INFO: 1 * Client out-bound request
1 > POST http://ws.cdyne.com/WeatherWS/Weather.asmx
1 > SOAPAction: "http://ws.cdyne.com/WeatherWS/GetCityWeatherByZIP"
1 > 
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header/>
    <SOAP-ENV:Body>
      <GetCityWeatherByZIP xmlns="http://ws.cdyne.com/WeatherWS/">
        <ZIP>59102</ZIP>
      </GetCityWeatherByZIP>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Dec 3, 2009 10:02:04 PM com.sun.jersey.api.client.filter.LoggingFilter log
INFO: 1 * Client in-bound response
1 < 200
1 < Content-Length: 762
1 < X-AspNet-Version: 2.0.50727
1 < X-Powered-By: ASP.NET
1 < Cache-Control: no-cache
1 < Pragma: no-cache
1 < Content-Type: text/xml; charset=utf-8
1 < Server: Microsoft-IIS/7.0
1 < Date: Fri, 04 Dec 2009 05:02:21 GMT
1 < Expires: -1
1 < 
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <GetCityWeatherByZIPResponse xmlns="http://ws.cdyne.com/WeatherWS/">
            <GetCityWeatherByZIPResult>
                <Success>true</Success>
                <ResponseText>City Found</ResponseText>
                <State>MT</State>
                <City>Billings</City>
                <WeatherStationCity>Billings</WeatherStationCity>
                <WeatherID>3</WeatherID>
                <Description>Mostly Cloudy</Description>
                <Temperature>16</Temperature>
                <RelativeHumidity>51</RelativeHumidity>
                <Wind>SW23</Wind>
                <Pressure>30.11F</Pressure>
                <Visibility />
                <WindChill />
                <Remarks />
            </GetCityWeatherByZIPResult>
        </GetCityWeatherByZIPResponse>
    </soap:Body>
</soap:Envelope>

City : Billings
Temperature : 16

In fact, this should work across the same way with any other JAX-RS Clients (I know there a quite a few). I have tried with the new kid on the block Apache Wink, which looks very interesting, still in incubation, but I am impressed with their documentation, as I hardly find useful docs with other projects in incubation stage. And the client APIs are similar to that of Jersey client, so it was fairly easy to write one using Wink Client. I will have to reserve another blog entry for exploring Wink’s USP.

import com.cdyne.ws.weatherws.GetCityWeatherByZIPResponse;
import org.apache.wink.client.ClientConfig;
import org.apache.wink.client.ClientResponse;
import org.apache.wink.client.Resource;
import org.apache.wink.client.RestClient;

import javax.ws.rs.core.Application;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.soap.*;
import java.util.HashSet;
import java.util.Set;

public class WinkClient {
    public static void main(String[] args) throws Exception {
        MessageFactory messageFactory = MessageFactory.newInstance();
        SOAPMessage message = messageFactory.createMessage();
        SOAPPart soapPart = message.getSOAPPart();
        SOAPEnvelope envelope = soapPart.getEnvelope();
        SOAPBody body = envelope.getBody();
        SOAPElement bodyElement = body.addChildElement(envelope.createName("GetCityWeatherByZIP", "", "http://ws.cdyne.com/WeatherWS/"));
        bodyElement.addChildElement("ZIP").addTextNode("59102");
        message.saveChanges();

        ClientConfig config = new ClientConfig();

        // Create new JAX-RS Application
        Application app = new Application() {
            @Override
            public Set<Class<?>> getClasses() {
                HashSet<Class<?>> set = new HashSet<Class<?>>();
                set.add(SoapProvider.class);
                return set;
            }
        };
        config.applications(app);

        RestClient client = new RestClient(config);

        // create the resource instance to interact with
        Resource resource = client.resource("http://ws.cdyne.com/WeatherWS/Weather.asmx");

        // issue the request
        ClientResponse cr = resource.contentType("text/xml").post(ClientResponse.class, message);
        message = cr.getEntity(SOAPMessage.class);

        JAXBContext ctx = JAXBContext.newInstance(GetCityWeatherByZIPResponse.class);
        Unmarshaller um = ctx.createUnmarshaller();
        GetCityWeatherByZIPResponse response = (um.unmarshal(message.getSOAPPart().getEnvelope().getBody().extractContentAsDocument(), GetCityWeatherByZIPResponse.class)).getValue();
        System.out.println("Response : " + response.getGetCityWeatherByZIPResult().getCity());
        System.out.println("Response : " + response.getGetCityWeatherByZIPResult().getTemperature());
    }
}

Here are the maven dependencies:

    <dependencies>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-client</artifactId>
            <version>1.1.4.1</version>
        </dependency>
        
        <dependency>
            <groupId>org.apache.wink</groupId>
            <artifactId>wink-client</artifactId>
            <version>1.0-incubating</version>
        </dependency>        
    </dependencies>

While there are better tools and frameworks which addresses the complexity of building SOAP messages, it was not a big deal to invoke web services from HTTP Clients, after all its just a HTTP POST.

Possibly Related Posts:


SSL enabled RESTful services are quite easier to develop and test using Jersey, Grizzly and RestTemplate.

Jersey (resource development)
Grizzly Web Server (resource configuration and deployment)
Spring 3 RestTemplate backed by Commons HTTP Client (resource access)

In a moment, you will notice how all these nicely fit the bill. Let us start with the POM for the maven fans.

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>org.springframework.web</artifactId>
            <version>3.0.0.M4</version>
        </dependency>
        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>1.1.2-ea</version>
        </dependency>
        <dependency>
            <groupId>com.sun.grizzly</groupId>
            <artifactId>grizzly-servlet-webserver</artifactId>
            <version>1.9.18a</version>
        </dependency>
        <dependency>
            <groupId>org.apache.log4j</groupId>
            <artifactId>com.springsource.org.apache.log4j</artifactId>
            <version>1.2.15</version>
        </dependency>
    </dependencies>

Configuring Log4j is very useful as you could see the commons Client debug messages and http wire headers which are quite useful for debugging in case if you were lost in translation.

Putting together all these pieces working did not take much of my time. I did not have to do anything fancy here as I just reused most of the sample code from the Jersey HTTPS sample and Commons HTTP Client SSL sample.

Lets dive into the Spring Config, which does most of the wiring of HTTP Client and RestTemplate.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="sslClient" class="spring3.restclient.RestSSLClient">
        <constructor-arg ref="restTemplate"/>
        <constructor-arg ref="credentials"/>
    </bean>

    <bean id="httpClientParams" class="org.apache.commons.httpclient.params.HttpClientParams">
        <property name="authenticationPreemptive" value="true"/>
        <property name="connectionManagerClass"
                  value="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager"/>
    </bean>
    <bean id="httpClient" class="org.apache.commons.httpclient.HttpClient">
        <constructor-arg ref="httpClientParams"/>
    </bean>
    <bean id="credentials" class="org.apache.commons.httpclient.UsernamePasswordCredentials">
        <constructor-arg value="admin"/>
        <constructor-arg value="adminadmin"/>
    </bean>
    <bean id="httpClientFactory" class="org.springframework.http.client.CommonsClientHttpRequestFactory">
        <constructor-arg ref="httpClient"/>
    </bean>

    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
        <constructor-arg ref="httpClientFactory"/>
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
            </list>
        </property>
    </bean>
</beans>

The below code configures a Grizzly Server with SSL support for server side certificates, Basic Auth filter and Jersey resource servlet.

import com.sun.grizzly.SSLConfig;
import com.sun.grizzly.http.embed.GrizzlyWebServer;
import com.sun.grizzly.http.servlet.ServletAdapter;
import com.sun.jersey.api.container.filter.RolesAllowedResourceFilterFactory;
import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.spi.container.servlet.ServletContainer;
import com.sun.jersey.samples.https_grizzly.auth.SecurityFilter;

import javax.ws.rs.core.UriBuilder;
import java.io.IOException;
import java.net.URI;

public class GrizzlyServer {

    private static GrizzlyWebServer webServer;

    public static final URI BASE_URI = getBaseURI();

    private static URI getBaseURI() {
        return UriBuilder.fromUri("https://localhost/").port(getPort(4463)).build();
    }

    private static int getPort(int defaultPort) {
        String port = System.getenv("JERSEY_HTTP_PORT");
        if (null != port) {
            try {
                return Integer.parseInt(port);
            } catch (NumberFormatException e) {
            }
        }
        return defaultPort;
    }

    protected static void startServer() {

        webServer = new GrizzlyWebServer(getPort(4463), ".", true);

        // add Jersey resource servlet

        ServletAdapter jerseyAdapter = new ServletAdapter();
        jerseyAdapter.addInitParameter("com.sun.jersey.config.property.packages", "server.https.auth;server.https.resource");
        jerseyAdapter.setContextPath("/");
        jerseyAdapter.setServletInstance(new ServletContainer());

        // add security filter (which handles http basic authentication)
        jerseyAdapter.addInitParameter(ResourceConfig.PROPERTY_CONTAINER_REQUEST_FILTERS, SecurityFilter.class.getName());
        // add authorization filter
        jerseyAdapter.addInitParameter(ResourceConfig.PROPERTY_RESOURCE_FILTER_FACTORIES, RolesAllowedResourceFilterFactory.class.getName());

        webServer.addGrizzlyAdapter(jerseyAdapter, new String[]{"/"});


        // Grizzly ssl configuration
        SSLConfig sslConfig = new SSLConfig();

        sslConfig.setNeedClientAuth(true); // don't work - known grizzly bug, will be fixed in 2.0.0

        // set up security context
        String keystore_server = Thread.currentThread().getContextClassLoader().getResource("keystore_server").getFile();
        String truststore_server = Thread.currentThread().getContextClassLoader().getResource("truststore_server").getFile();

        sslConfig.setKeyStoreFile(keystore_server); // contains server keypair
        sslConfig.setKeyStorePass("secret");
        sslConfig.setTrustStoreFile(truststore_server); // contains client certificate
        sslConfig.setTrustStorePass("secret");

        webServer.setSSLConfig(sslConfig);

        // turn server side client certificate authentication on

//        ((SSLSelectorThread) webServer.getSelectorThread()).setNeedClientAuth(true);

        try {
            // start Grizzly embedded server //
            System.out.println(String.format("Jersey app started with WADL at %sapplication.wadl", BASE_URI));
            webServer.start();
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
    }

    protected static void stopServer() {
        webServer.stop();
    }

    public static void main(String[] args) throws InterruptedException, IOException {
        startServer();
        System.out.println("Hit return to stop...");
        System.in.read();
        stopServer();
    }
}

Here’s slightly modified version of the sample Jersey Security filter which would handle the HTTP basic authentication on the server. The auth helper classes (AuthenticationExceptionMapper, AuthenticationException) are found here.

package com.sun.jersey.samples.https_grizzly.auth;

import com.sun.jersey.api.container.MappableContainerException;
import com.sun.jersey.core.util.Base64;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerRequestFilter;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import java.security.Principal;

public class SecurityFilter implements ContainerRequestFilter {

    @Context
    UriInfo uriInfo;
    private static final String REALM = "HTTPS Example authentication";

    public ContainerRequest filter(ContainerRequest request) {
        User user = authenticate(request);
        request.setSecurityContext(new Authorizer(user));
        return request;
    }

    private User authenticate(ContainerRequest request) {
        // Extract authentication credentials
        String authentication = request.getHeaderValue(ContainerRequest.AUTHORIZATION);
        if (authentication == null) {
            throw new MappableContainerException
                    (new AuthenticationException("Authentication credentials are required", REALM));
        }
        if (!authentication.startsWith("Basic ")) {
            return null;
            // additional checks should be done here
            // "Only HTTP Basic authentication is supported"
        }
        authentication = authentication.substring("Basic ".length());
        String[] values = new String(Base64.base64Decode(authentication)).split(":");
        if (values.length < 2) {
            throw new WebApplicationException(400);
            // "Invalid syntax for username and password"
        }
        String username = values&#91;0&#93;;
        String password = values&#91;1&#93;;
        if ((username == null) || (password == null)) {
            throw new WebApplicationException(400);
            // "Missing username or password"
        }

        // Validate the extracted credentials
        User user = null;

        if (username.equals("john") && password.equals("secret")) {
            user = new User("john", "user");
            System.out.println("USER 'John Doe' AUTHENTICATED");
        } else if (username.equals("jane") && password.equals("secret")) {
            user = new User("jane", "user");
            System.out.println("USER 'Jane Doe' AUTHENTICATED");
        } else if (username.equals("admin") && password.equals("adminadmin")) {
            user = new User("admin", "admin");
            System.out.println("ADMIN AUTHENTICATED");
        } else {
            System.out.println("USER NOT AUTHENTICATED");
            throw new MappableContainerException(new AuthenticationException("Invalid username or password\r\n", REALM));
        }
        return user;
    }

    public class Authorizer implements SecurityContext {

        private User user;
        private Principal principal;

        public Authorizer(final User user) {
            this.user = user;
            this.principal = new Principal() {

                public String getName() {
                    return user.username;
                }
            };
        }

        public Principal getUserPrincipal() {
            return this.principal;
        }

        public boolean isUserInRole(String role) {
            return (role.equals(user.role));
        }

        public boolean isSecure() {
            return "https".equals(uriInfo.getRequestUri().getScheme());
        }

        public String getAuthenticationScheme() {
            return SecurityContext.BASIC_AUTH;
        }
    }

    public class User {

        public String username;
        public String role;

        public User(String username, String role) {
            this.username = username;
            this.role = role;
        }
    }
}
&#91;/sourcecode&#93;

The resource class is very simple. The resource methods are access controlled using the JSR-250 annotation @RolesAllowed. The methods are self-explanatory and they are just coded for illustration, not a fool-proof implementation. In this sample, the Grizzly server would perform server-side certificate authentication and HTTP Basic authentication, in addition to basic authorization checks.

&#91;sourcecode language='java'&#93;
import com.sun.jersey.core.util.Base64;

import javax.annotation.security.RolesAllowed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/")
public class HttpsResource {

    @GET
    @RolesAllowed({"admin"})
    @Path("/locate/{username}")
    public Response getUserLocation(@Context HttpHeaders headers, @PathParam("username") String username) {
        // you can get username from HttpHeaders
        System.out.println("Service: GET / User Location for : " + username + " requested by " + getUser(headers));
        return Response.ok("Billings, Montana").type(MediaType.TEXT_PLAIN).build();
    }

    @GET
    @RolesAllowed({"admin", "user"})
    public Response getUserPin(@Context HttpHeaders headers) {
        // you can get username from HttpHeaders
        System.out.println("Service: GET / User Pin for: " + getUser(headers));
        return Response.ok("1234").type(MediaType.TEXT_PLAIN).build();
    }

    private String getUser(HttpHeaders headers) {
        String auth = headers.getRequestHeader("authorization").get(0);

        auth = auth.substring("Basic ".length());
        String&#91;&#93; values = new String(Base64.base64Decode(auth)).split(":");

        String username = values&#91;0&#93;;
        String password = values&#91;1&#93;;

        return username;
    }
}
&#91;/sourcecode&#93;

The following steps guide to create sample client and server certificates using the JDK keytool utility. The self-signed certificates are used for demonstration purposes only. In reality, this would be performed by a Certificate Authority (for ex: Verisign).

<strong><ul>generate client and server keys:</ul></strong>

keytool -genkey -keystore keystore_client -alias clientKey -dname "CN=www.aruld.info, OU=R&D, O=Vasun Technologies, L=Billings, ST=Montana, C=US"
keytool -genkey -keystore keystore_server -alias serverKey -dname "CN=www.aruld.info, OU=R&D, O=Vasun Technologies, L=Billings, ST=Montana, C=US"

<strong><ul>generate client and server certificates:</ul></strong>

keytool -export -alias clientKey -rfc -keystore keystore_client > client.cert
keytool -export -alias serverKey -rfc -keystore keystore_server > server.cert

<strong><ul>import certificates to corresponding truststores:</ul></strong>

keytool -import -alias clientCert -file client.cert -keystore truststore_server
keytool -import -alias serverCert -file server.cert -keystore truststore_client


SSL helper classes (AuthSSLProtocolSocketFactory, AuthSSLX509TrustManager, AuthSSLInitializationError) for the client-side are used from the Commons Client SSL <a href="http://svn.apache.org/viewvc/httpcomponents/oac.hc3x/trunk/src/contrib/org/apache/commons/httpclient/contrib/ssl/">contrib</a> samples.

RestTemplate is injected into the RestSSLClient which uses the Commons Client APIs to set the credentials and configures the keystore and truststore on the client-side.


import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.contrib.ssl.AuthSSLProtocolSocketFactory;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.springframework.http.client.CommonsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.HashMap;

public class RestSSLClient {
    private final RestTemplate restTemplate;
    private final HttpClient client;
    private Credentials credentials;
    private static final int HTTPS_PORT = 4463;
    private static final String HTTPS_GET = "https://localhost:4463/";
    private static final String HTTPS_GET_LOCATION = "https://localhost:4463/locate/{username}";
    private static final String HTTPS = "https";
    private static final String HTTPS_HOST = "localhost";

    public RestSSLClient(RestTemplate restTemplate, Credentials credentials) {
        this.restTemplate = restTemplate;
        this.credentials = credentials;
        CommonsClientHttpRequestFactory factory = (CommonsClientHttpRequestFactory) restTemplate.getRequestFactory();
        this.client = factory.getHttpClient();
        client.getState().setCredentials(AuthScope.ANY, credentials);
        try {
            URL keystore_client = Thread.currentThread().getContextClassLoader().getResource("keystore_client").toURI().toURL();
            URL truststore_client = Thread.currentThread().getContextClassLoader().getResource("truststore_client").toURI().toURL();
            ProtocolSocketFactory protocolSocketFactory = new AuthSSLProtocolSocketFactory(keystore_client, "secret",
                    truststore_client, "secret");
            Protocol authhttps = new Protocol(HTTPS, protocolSocketFactory, HTTPS_PORT);
            Protocol.registerProtocol(HTTPS, authhttps);
            client.getHostConfiguration().setHost(HTTPS_HOST, HTTPS_PORT, authhttps);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }

    public void setCredentials(String user, String pass) {
        this.credentials = new UsernamePasswordCredentials(user, pass);
        client.getState().setCredentials(AuthScope.ANY, credentials);
    }

    public String get() {
        return restTemplate.getForObject(HTTPS_GET, String.class);
    }

    public String getLocation(String user) {
        Map<String, String> vars = new HashMap<String, String>();
        vars.put("username", user);
        return restTemplate.getForObject(HTTPS_GET_LOCATION, String.class, vars);
    }
}

The test code which invokes the SSL configured resource is shown below.

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Spring3RestSSLClient {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-ssl.xml");
        RestSSLClient client = applicationContext.getBean("sslClient", RestSSLClient.class);
        System.out.println("John's Location : " + client.getLocation("john"));
        System.out.println("Jane's Location : " + client.getLocation("jane"));
        client.setCredentials("john", "secret");
        System.out.println("John Doe's Pin : " + client.get());
        client.setCredentials("jane", "secret");
        System.out.println("Jane Doe's Pin : " + client.get());
    }
}

WADL for this resource can be accessed from https://localhost:4463/application.wadl. You could access the URL from a browser as the server side client certificate authentication is disabled in the GrizzlyServer. (Uncommenting line # 70 would enable server side client cert auth, but this would force the browser to use the generated client keys). Test it yourself, you would be presented with a basic auth dialog (valid user/pass/role: admin/adminadmin/admin, john/secret/user, jane/secret/user) and you could access the resource methods with specified roles. I have tested with Firefox and Chrome. Enjoy!

Possibly Related Posts:


The central API for accessing RESTful services in Spring 3 is RestTemplate. It is like any other template mechanism provided by Spring for the client side access. The default implementation uses the java.net package for creating HTTP requests. RestTemplate can be backed by Commons HttpClient using ClientHttpRequestFactory. Using Commons HttpClient as the backend implementation supports basic authentication in the requests. The javadocs were the single source of information for Spring3 REST support until M2, but you can find the latest reference documentation with M3 release here. Chapter 18 covers REST support in Spring 3. You can also read Arjen’s blog posts here and here which outlines the REST support in Spring 3 both on the server-side and client-side.

I was playing with the RestTemplate and was quite impressed with it as it comes handy for Spring developers. But, this implementation is no different than most other REST Client APIs. Long story short, this is yet another attempt to provide a non-standard Client for accessing RESTful resources. I am leaning more towards the need for a standard JAX-RS client API and I hope JAX-RS 2.0 fuels that interest. Lets explore with an example how Spring 3 provides native support for accessing RESTful resources using RestTemplate.

Twitter is one of the most widely used service which has a decent REST API with basic authentication.

Lets start with the POM dependencies. I had built the latest Spring3 M3 snapshot on my box, but you should be able to fetch them from Spring maven snapshots repository.

<repositories>
    <repository>
        <id>SpringSource Enterprise Bundle Repository - External Bundle Milestones</id>
        <url>http://repository.springsource.com/maven/bundles/milestone</url>
    </repository>
    <repository>
        <id>SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases</id>
        <url>http://repository.springsource.com/maven/bundles/release</url>
    </repository>
    <repository>
        <id>SpringSource Enterprise Bundle Repository - External Bundle Releases</id>
        <url>http://repository.springsource.com/maven/bundles/external</url>
    </repository>
</repositories>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
            </configuration>
        </plugin>
    </plugins>
</build>
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>org.springframework.web</artifactId>
        <version>3.0.0.M3</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.ws</groupId>
        <artifactId>org.springframework.xml</artifactId>
        <version>1.5.5.A</version>
    </dependency>
    <dependency>
        <groupId>org.apache.log4j</groupId>
        <artifactId>com.springsource.org.apache.log4j</artifactId>
        <version>1.2.15</version>
    </dependency>
    <dependency>
        <groupId>commons-httpclient</groupId>
        <artifactId>commons-httpclient</artifactId>
        <version>3.1</version>
    </dependency>
</dependencies>

The Spring configuration defines the beans required for this sample.

<?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:oxm="http://www.springframework.org/schema/oxm"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">
    <bean id="twitterClient" class="spring3.restclient.TwitterClient">
        <constructor-arg ref="restTemplate"/>
        <constructor-arg ref="credentials"/>
    </bean>

    <bean id="httpClientParams" class="org.apache.commons.httpclient.params.HttpClientParams">
        <property name="authenticationPreemptive" value="true"/>
        <property name="connectionManagerClass"
                  value="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager"/>
    </bean>
    <bean id="httpClient" class="org.apache.commons.httpclient.HttpClient">
        <constructor-arg ref="httpClientParams"/>
    </bean>
    <bean id="credentials" class="org.apache.commons.httpclient.UsernamePasswordCredentials">
        <constructor-arg value="username"/>
        <constructor-arg value="password"/>
    </bean>
    <bean id="httpClientFactory" class="org.springframework.http.client.CommonsClientHttpRequestFactory">
        <constructor-arg ref="httpClient"/>
    </bean>

    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
        <constructor-arg ref="httpClientFactory"/>

        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
                    <property name="marshaller" ref="jaxbMarshaller"/>
                    <property name="unmarshaller" ref="jaxbMarshaller"/>
                </bean>
                <bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
            </list>
        </property>
    </bean>

    <bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
        <property name="classesToBeBound">
            <list>
                <value>twitter.model.Statuses</value>
            </list>
        </property>
    </bean>
</beans>

MarshallingHttpMessageConverter is used to marshal/unmarshal JAXB beans. Statuses is a JAXB bean which is bound to the response returned by GET on the Twitter URI https://twitter.com/statuses/friends_timeline.xml. FormHttpMessageConverter is used to construct form parameters to POST on the Twitter URI https://twitter.com/statuses/update.xml.

Now, we will see the RestTemplate in action. You can see the code is just a one liner.

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.auth.AuthScope;
import org.springframework.http.client.CommonsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import org.springframework.util.MultiValueMap;
import org.springframework.util.LinkedMultiValueMap;
import twitter.model.Statuses;

import java.util.HashMap;
import java.util.Map;

public class TwitterClient {

    private final RestTemplate restTemplate;

    private final Credentials credentials;

    private static final String twitterGet = "https://twitter.com/statuses/friends_timeline.xml?count={count}";
    private static final String twitterPost = "https://twitter.com/statuses/update.xml";

    public TwitterClient(RestTemplate restTemplate, Credentials credentials) {
        this.restTemplate = restTemplate;
        this.credentials = credentials;
        CommonsClientHttpRequestFactory factory = (CommonsClientHttpRequestFactory) restTemplate.getRequestFactory();
        HttpClient client = factory.getHttpClient();
        client.getState().setCredentials(AuthScope.ANY, credentials);
    }

    public Statuses getStatuses() {
        Map<String, String> vars = new HashMap<String, String>();
        vars.put("count", "5");
        return restTemplate.getForObject(twitterGet, Statuses.class, vars);
    }

    public void setStatus(String status) {
        MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
        map.add("status", status);
        restTemplate.postForLocation(twitterPost, map);
    }
}

The test code which posts the status to your Twitter account is shown below.

public class Spring3RestClientTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        TwitterClient twitter = applicationContext.getBean("twitterClient", TwitterClient.class);
        twitter.setStatus("Spring RestTemplate rocks!");
        Statuses statuses = twitter.getStatuses();
        for (Statuses.Status status : statuses.getStatus()) {
            System.out.println("Text : " + status.getText());
            System.out.println("User : " + status.getUser().getScreenName());
        }
    }
}

Here is an example output of the above test which lists recent five status messages from Twitter:
=====================================================
Text : Spring RestTemplate rocks!
User : aruld
Text : Just finished celebrating with the SpringSource & Hyperic teams at Tres Agaves. Really good to meet everyone! http://twitpic.com/4l1hb
User : cbeams
Text : 8 Java Puzzlers for JavaOne done. Wow. Soon we’ll scrape right through the bottom of the barrel.
User : gafter
Text : Disappointed my Maredsous 8 is all gone. I should’ve bought more.
User : dandiep
Text : Headed to San Francisco for a week of Core Spring training & looking forward to it!
User : cbeams
=====================================================

RestTemplate does serves its purpose, but it could be improved to support additional convenient methods for accessing URIs with query parameters. The other thing I noticed is about making HTTP POST with a name-value pair using postForLocation API. I could not find any details from the documentation so far. For instance, I would like to do a post to the URI http://twitter.com/statuses/update.xml with the form data “status=This is my current status” sent in the HTTP body. I am not sure whether this is possible with the current implementation. I will dig into this further and keep posted on what I find.

Update (5/4): Thanks to Arjen for clarifying the URITemplate use within query parameters and the FormHttpMessageConverter for using Form parameters. The blog has been updated to use these techniques. You could POST a twitter message just fine 🙂

Update (5/10): Updated the reference documentation to the official M3 build from SpringSource and updated the maven POM to use the M3 dependency.

Possibly Related Posts:


Jersey 1.0.3 was released this week. This release has quite a few interesting new features and improvements to some of its existing functionality. Paul’s blog entry gives the specifics of this release. One of the cool features in this release is the ability to inject WadlApplicationContext in resources. This provides access to the WADL JAXB representation for your restful application. Paul already discussed about its usage in the Jersey dev mailing list. I wanted to see all these in action and you won’t believe that it took just few minutes to see styled WADL documentation in action.

The following URI paths renders XSL styled WADL documentation for resources :

http://localhost:9998/application.wadl

http://localhost:9998/wadl

Here is a preview of the documentation (This works in Chrome out of the box, no luck with Firefox and IE):

Jersey WADL documentation

I used Mark’s WADL to HTML documentation stylesheet for styling the documentation.

The HTTP response for WADL GET recorded by Firebug:

HTTP Response for WADL GET

Here is the POM for interested:

    <dependencies>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.1</version>
        </dependency>

        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.1.10</version>
        </dependency>

        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>1.0.3</version>
        </dependency>

        <dependency>
            <groupId>com.sun.jersey.test.framework</groupId>
            <artifactId>jersey-test-framework</artifactId>
            <version>1.0.3</version>
            <scope>test</scope>
        </dependency>

The WadlResource below shows how the WadlApplicationContext injection happens and the JAXBContext is retrieved from WadlApplicationContext. The marshaller allows you to set the property which can be used to specify an XML preamble, in this case WADL to HTML documentation stylesheet embedded in the XML headers. The rest all is the usual stuff you know.

@Produces({"application/vnd.sun.wadl+xml", "application/xml"})
@Singleton
@Path("wadl")
public class WadlResource {

    private static final Logger LOGGER = Logger.getLogger(WadlResource.class.getName());

    private static final String XML_HEADERS = "com.sun.xml.bind.xmlHeaders";

    private WadlApplicationContext wadlContext;

    private Application application;

    private byte[] wadlXmlRepresentation;

    public WadlResource(@Context WadlApplicationContext wadlContext) {
        this.wadlContext = wadlContext;
        this.application = wadlContext.getApplication();
    }

    @GET
    public synchronized Response getWadl(@Context UriInfo uriInfo) {
        if (wadlXmlRepresentation == null) {
            if (application.getResources().getBase() == null) {
                application.getResources().setBase(uriInfo.getBaseUri().toString());
            }
            try {
                final Marshaller marshaller = wadlContext.getJAXBContext().createMarshaller();
                marshaller.setProperty(XML_HEADERS, "<?xml-stylesheet type='text/xsl' href='http://www.mnot.net/webdesc/wadl_documentation.xsl'?>");
                marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
                final ByteArrayOutputStream os = new ByteArrayOutputStream();
                marshaller.marshal(application, os);
                wadlXmlRepresentation = os.toByteArray();
                os.close();
            } catch (Exception e) {
                LOGGER.log(Level.WARNING, "Could not marshal wadl Application.", e);
                return javax.ws.rs.core.Response.ok(application).build();
            }
        }
        return Response.ok(new ByteArrayInputStream(wadlXmlRepresentation)).build();
    }
}

MyWadlResource extends from WadlResource with the relative URL at “application.wadl”. There is already a patch submitted by James Strachan which will allow using WADL with implicit views. I hope this becomes available for the next 1.1.0-ea release.

@Path("application.wadl")
public class MyWadlResource extends WadlResource {
  public MyWadlResource(@Context WadlApplicationContext wadlContext) {
    super(wadlContext);
  }
}

The usual standalone Server code is shown below.

public class Server {
    public static void main(String[] args) throws IOException {
        final String baseUri = "http://localhost:9998/";
        final Map<String, String> initParams = new HashMap<String, String>();
        initParams.put("com.sun.jersey.config.property.packages", "jersey.wadl.resources");
        System.out.println("Starting grizzly...");
        SelectorThread threadSelector = GrizzlyWebContainerFactory.create(baseUri, initParams);
        System.out.println(String.format("Jersey app started with WADL available at %sapplication.wadl or %swadl\n"
                + "Try out %s\nHit enter to stop it...", baseUri, baseUri, baseUri));
        System.in.read();
        threadSelector.stopEndpoint();
        System.exit(0);
    }
}

Here is a simple test written using the new Jersey test framework and by default it deploys the resources to the Grizzly container. The Application class is serialized as a JAXB bean. You then have access to all the WADL components.

public class WadlTest extends JerseyTest {

  public WadlTest() throws Exception {
    super("jersey.wadl.resources");
  }

  @Test
  public void wadlGet() {
    ClientResponse cr = webResource.path("wadl").get(ClientResponse.class);
    Application a = cr.getEntity(com.sun.research.ws.wadl.Application.class);
    Method m = (Method)a.getResources().getResource().get(0).getMethodOrResource().get(0);
    Response r = m.getResponse();
    List<JAXBElement<RepresentationType>> representations = r.getRepresentationOrFault();
    for (JAXBElement<RepresentationType> representation : representations) {
      RepresentationType type = representation.getValue();
      System.out.println("MediaType : " + type.getMediaType());
    }
  }
}

The other notable support in this release is integration with Guice 2.0. Maturity and quality is always the driving factor behind every Jersey release. No compromises whatsoever. Well done Paul and team!

The project sources can be downloaded from here.

Possibly Related Posts:


I was playing with CXF 2.2 over the weekend. I would like to share my experience in building a simple blogger service using CXF which provides seamless access to SOAP and REST web services. You would soon realize how services design and development has become easier with this new CXF release. Lets dive into the crux.

The blogger service exposes reading and writing operations. All blogging operations (CRUD) are exposed as REST and read operations are exposed as SOAP. This approach enables service containment and provides controlled access to services. This service produces XML and JSON content and the negotiation is done by the client.

The class hierarchy is shown below.

Blogger class hierarchy

Maven dependencies for this project are:

        <dependency>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <groupId>org.apache.cxf</groupId>
            <version>2.2</version>
        </dependency>
        <dependency>
            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
            <groupId>org.apache.cxf</groupId>
            <version>2.2</version>
        </dependency>
        <dependency>
            <artifactId>servlet-api</artifactId>
            <groupId>javax.servlet</groupId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <artifactId>cxf-rt-transports-http</artifactId>
            <groupId>org.apache.cxf</groupId>
            <version>2.2</version>
        </dependency>
        <dependency>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <groupId>org.apache.cxf</groupId>
            <version>2.2</version>
        </dependency>

BlogReader interface enables REST and SOAP access for the blogger service read operations.

public interface BlogReader {
    @WebMethod
    @GET
    @Path("{id}")
    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    public Entry getEntry(@PathParam("id") Long id);

    @WebMethod
    @GET
    @Path("/list")
    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    public Entries getEntries();    
}

BlogWriter interface enables REST access for the blogger service write operations.

public interface BlogWriter {
    @POST
    Response addEntry(Entry entry);

    @PUT
    Response updateEntry(Entry entry);

    @DELETE
    @Path("{id}")
    Response deleteEntry(@PathParam("id") Long id);
}

Blogger interface unifies SOAP and REST access to the blogger service.

@Path("/")
@WebService
public interface Blogger extends BlogReader, BlogWriter {
}

Here is a trivial implementation of the blogger service. This implementation shows how resources can be made service oriented without any extra effort.

public class BloggerImpl implements Blogger {
    static Map<Long, Entry> blogDb = new TreeMap<Long, Entry>();
    private AtomicLong counter = new AtomicLong();

    public Response addEntry(Entry entry) {
        System.out.println("adding entry..");
        entry.setId(counter.incrementAndGet());
        blogDb.put(entry.getId(), entry);
        System.out.println("Created blog entry " + entry.getId());
        return Response.created(URI.create("/" + entry.getId())).build();
    }

    public Response updateEntry(Entry entry) {
        System.out.println("Updated blog entry " + entry.getId());
        Entry oldEntry = blogDb.get(entry.getId());
        Response r;
        if (oldEntry != null) {
            r = Response.ok().build();
            blogDb.put(entry.getId(), entry);
        } else {
            r = Response.notModified().build();
        }
        return r;
    }

    public Response deleteEntry(Long id) {
        System.out.println("Removed blog entry " + id);
        Entry entry = blogDb.get(id);
        Response r;
        if (entry != null) {
            r = Response.ok().build();
            blogDb.remove(id);
        } else {
            r = Response.notModified().build();
        }
        return r;        
    }

    public Entry getEntry(@PathParam("id") Long id) {
        System.out.println("Fetching blog entry " + id);
        Entry entry = blogDb.get(id);
        if (entry == null) {
          throw new WebApplicationException(Response.Status.NOT_FOUND);
        }
        return entry;
    }

    public Entries getEntries() {
        Entries entries = new Entries();
        entries.setEntry(blogDb.values());
        return entries;
    }
}

Entry and Entries classes are simple JAXB beans.

The Server code starts both the CXF REST and SOAP services which uses the embedded Jetty server. You could easily configure the content filtering just by suffixing to the URI (.xml or .json) as defined in the extension mappings.

public class Server {
    public static void main(String[] args) {
        startSoapServer();
        startRestServer();
    }

    private static void startRestServer() {
        JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
        sf.setResourceClasses(Blogger.class);
        sf.getInInterceptors().add(new LoggingInInterceptor());
        sf.getOutInterceptors().add(new LoggingOutInterceptor());
        sf.setResourceProvider(Blogger.class, new SingletonResourceProvider(new BloggerImpl()));
        sf.setAddress("http://localhost:9000/rest/blog");
        Map<Object, Object> mappings = new HashMap<Object, Object>();
        mappings.put("xml", "application/xml");
        mappings.put("json", "application/json");
        sf.setExtensionMappings(mappings);
        sf.create();
        System.out.println("Rest Server started @ " + sf.getAddress());
    }

    private static void startSoapServer() {
        JaxWsServerFactoryBean sf = new JaxWsServerFactoryBean();
        sf.setServiceClass(BlogReader.class);
        BloggerImpl blogger = new BloggerImpl();
        sf.setServiceBean(blogger);
        sf.setAddress("http://localhost:9000/soap/blog");
        sf.getInInterceptors().add(new LoggingInInterceptor());
        sf.getOutInterceptors().add(new LoggingOutInterceptor());
        sf.create();
        System.out.println("Soap Server started @ " + sf.getAddress());
    }
}

CXF JAXRS client API comes in different flavors. In this example, I used the WebClient which acts like a browser in interacting with web resources. The API client.back(true) if true then goes back to baseURI otherwise it goes back to a previous path segment, just like browsers. The tests are self-explanatory. I was able to perform all the CRUD operations using the WebClient API.

public class RestClient {
    public static void main(String[] args) {
        String baseUri = "http://localhost:9000/rest/blog";
        WebClient client = WebClient.create(baseUri);

        Entry entry = new Entry();
        entry.setDate(new Date());
        entry.setTitle("CXF in Action!");
        entry.setContent("CXF rocks!");
        Response response = client.post(entry);

        System.out.println("POST Response : " + response.getStatus());
        System.out.println("Location : " + response.getMetadata().getFirst("Location"));

        client.path("/1.xml");
        entry = client.get(Entry.class);
        System.out.println("entry.id : " + entry.getId() );

        client.back(true);
        entry.setContent("CXF 2.2 rocks!");
        response = client.put(entry);
        System.out.println("PUT Response : " + response.getStatus());

        client.path("/1.xml");
        entry = client.get(Entry.class);
        System.out.println("entry.id : " + entry.getContent());

        client.back(true);
        client.path("/1.xml");
        response = client.delete();
        System.out.println("DELETE Response : " + response.getStatus());

        client.back(true);
        response = client.post(entry);
        System.out.println("POST Response : " + response.getStatus());
        System.out.println("Location : " + response.getMetadata().getFirst("Location"));
    }
}

The SoapClient queries the added blog entries from the REST interface.

public class SoapClient {
    public static void main(String[] args) {
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.getInInterceptors().add(new LoggingInInterceptor());
        factory.getOutInterceptors().add(new LoggingOutInterceptor());

        factory.setServiceClass(BlogReader.class);
        factory.setAddress("http://localhost:9000/soap/blog");
        BlogReader blogger = (BlogReader) factory.create();
        Entry entry = blogger.getEntry(2L);
        System.out.println("entry title : " + entry.getTitle());
        System.out.println("entry content : " + entry.getContent());
    }
}

But, this gives you an idea how CXF services can promote reusability across various design approaches and making life simpler for developers. I know this is fairly basic example and definitely requires further refining. I will keep this for another post. Stay tuned.

[Update: 3/25] The delete method would throw “java.net.ProtocolException: HTTP method DELETE doesn’t support output” due to a bug in HttpConduit in CXF 2.2. This got fixed in the latest trunk. Thanks to Sergey for fixing this. In order to use the 2.2.1 snapshot repository, you need to define the following maven snapshot repository in your POM with dependency version 2.2.1-SNAPSHOT.

        <repository>
            <name>Apache CXF snapshots repository</name>
            <url>https://repository.apache.org/content/repositories/snapshots</url>
            <id>cxf-snapshots</id>
        </repository>

Possibly Related Posts: