Search This Blog

Showing posts with label Restlet. Show all posts
Showing posts with label Restlet. Show all posts

Monday, August 4, 2008

Restlet, JAXRS, JSR 311, Maven, Spring and more.

I have been wanting to alter my Restlet example that utilizes Spring, Restlet and Maven to use JAXRS or JSR 311 API. The Restlet project supports JAXRS.

For the sake of simplicity, I did not change the client code in anyway, i.e., preferring to use the Restlet API for invocations. In addition JAXRS does not provide for any Client API specifications ;-)

I changed the OrderResource as follows:
@Component @Path("/order")

public class OrderResource {
private static final Logger log = Logger.getLogger(OrderResource.class);

@Autowired private OrderService orderService;
@Autowired private MapperIF beanMapper;

public OrderResource() {
super();
}

private OrderDTO persistOrder(OrderDTO orderDTO) {
if (log.isDebugEnabled()) {
log.debug("Persisting order:" + orderDTO);
}

Order order = (Order) beanMapper.map(orderDTO, Order.class);

if (log.isDebugEnabled()) {
log.debug("Mapped Order" + order);
}

orderService.persist(order);

if (log.isDebugEnabled()) {
log.debug("Mapping persisted order to OrderDTO:" + order);
}
orderDTO = (OrderDTO) beanMapper.map(order, OrderDTO.class);

if (log.isDebugEnabled()) {
log.debug("Returning mapped order:" + orderDTO);
}

return orderDTO;
}

@Path("/{id}") @ConsumeMime("application/xml") @PUT public void updateOrder(
@PathParam("id") String id, OrderDTO orderDTO) {
if (log.isDebugEnabled()) {
log.debug("Enter Update Order, Id=" + id + ", Order DTO:" + orderDTO);
}
Long idLong = new Long(id);
orderDTO.setOrderId(idLong);
orderDTO = persistOrder(orderDTO);

if (log.isDebugEnabled()) {
log.debug("Order Persisted:" + orderDTO);
}
}

@ProduceMime("application/xml") @ConsumeMime("application/xml") @POST public OrderDTO storeOrder(
OrderDTO orderDTO) {
orderDTO = persistOrder(orderDTO);

return orderDTO;
}

@GET @Path("/{id}") @ProduceMime("application/xml") public OrderDTO getOrder(
@PathParam("id") String id) throws OrderNotFoundException {
Long orderId = new Long(id);

Order order = null;

try {
order = orderService.getOrder(orderId);
}
catch (OrderNotFoundException nfe) {
log.error("Order Not Found", nfe);
throw nfe;
}

log.info("Order found..");

OrderDTO orderDTO = (OrderDTO) beanMapper.map(order, OrderDTO.class);

return orderDTO;
}

@DELETE @Path("/{id}") public void deleteOrder(@PathParam("id") String id) {
Long orderId = new Long(id);
orderService.delete(orderId);
}

public void validate() {
Assert.notNull(orderService);
}
}


Notable Changes to the OrderResource:


  1. The @Path annotation on the OrderResource class tells the container that the OrderResource will handle calls of the context /order.
  2. The @Path annotation on some of the methods of the OrderResource denote specifics of the path.
  3. @ConsumeMime and @ProduceMime annotations indicate the mime types that will be consumed or produced by the method respectively.
  4. @POST, @GET, @PUT, @DELETE denote the different HTTP methods and a method annotated with one of these annotations will handle the request of the specific type.
  5. @PathParam denotes a parameter that will be available for the method.

In the above example, we have eliminated code that extends a Restlet Resource class. We have used annotations to specify what HTTP methods the Resource supports. We have also eliminated the Representation concept from the methods in favor of @ProduceMine and @ConsumeMine which help define what mime types can be produced and consumed by the method respectively. JAXRS introduces the concept of Providers that help in marshalling/unmarshalling different mime types. Providers are annotated with the @Provider annotation. In addition, in the case of Exceptions, Exception Providers also can be developed that determine the response to be provided to a client.

If a method is annotated with @ConsumeMime or @ProduceMime of type "application/xml" and the object part of the method argument or return type is a JAXB object, i.e., an object that has the annotation @XmlRootElement, automatic JAXB marshalling is accomplished. The OrderDTO is one such object.


From the example, we also had a ProductResource. The ProductResource from the earlier example only supported the MIME type of "application/jspon". The updated ProductResource is shown below:

@Component @Path("/products") public class ProductsResource {

private static final Logger log = Logger.getLogger(ProductsResource.class);

@Autowired private ProductService productService;
@Autowired private MapperIF beanMapper;

private Set map(Set products) {
Set productDTOs = new HashSet();

for (Product product : products) {
ProductDTO productDTO = (ProductDTO) beanMapper.map(product, ProductDTO.class);
productDTOs.add(productDTO);
}

return productDTOs;
}

/**
* Gets a {@link ProductListDTO} of Products that are supported.
*
* @return a List of Products
*/
@GET @ProduceMime( { "application/json" }) public ProductListDTO getProducts() {
log.debug("Enter getProducts()");

Set products = productService.getProducts();
Set productDTOs = map(products);

if (log.isDebugEnabled()) {
log.debug("Returning Products:" + productDTOs);
}

return new ProductListDTO(productDTOs);
}
}


Unlike in JAXB where the annotations determine the marshalling sematics, for the JSON marshalling, I had to do some customizationwhere we specifically detail how the marshalling should occur.

I have been discussing the operation with Jerome on the Restlet Discussion forum and maybe it will become easier to just specify the mime type and not have to worry about the conversion.

Until then, we can accomplish the conversion to JSON using a custom Provider as shown below:
@ProduceMime("application/json")

@Provider
public class ProductProvider implements
MessageBodyWriter {
private static final Logger log = Logger.getLogger(ProductProvider.class);

public long getSize(ProductListDTO t) {
return -1;
}

public boolean isWriteable(Class type, Type genericType, Annotation[] annotations) {
return true;
}

public void writeTo(ProductListDTO t, Class type, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException,
WebApplicationException {

log.debug("Write To of ProductProvider invoked...");

JSONArray jsonArray = new JSONArray();

for (ProductDTO product : t.getProducts()) {
jsonArray.put(product.getProductId()).put(product.getName()).put(product.getDescription());
}

OutputStreamWriter writer = new OutputStreamWriter(entityStream);

try {
writer.write(jsonArray.toString());
writer.flush();
}
catch (IOException e) {
log.error("Error Writing JSON Array:", e);
throw e;
}

log.debug("Exit Write To of ProductProvider");
}
}



When an Order is not found, an OrderNotFoundException is thrown. The same is translated to a Response of HTTP code 404 to the consumer via the following Provider:





@Provider public class OrderNotFoundProvider implements ExceptionMapper {

public Response toResponse(OrderNotFoundException exception) {
return Response.status(Response.Status.NOT_FOUND).build();
}
}




So how do all there components tie together. I have largely based the glue code on a very nice example from the Restlet WIKI about JAXRS Support. I have an OrderConfig class as shown below that indicates the supported MediaType mappings, the Resource Classes and the Custom Provider classes:





public class OrderConfig extends ApplicationConfig {

public Set> getResourceClasses() {
Set> rrcs = new HashSet>();

rrcs.add(OrderResource.class);
rrcs.add(ProductsResource.class);

return rrcs;
}

@Override public Map getMediaTypeMappings() {
Map map = new HashMap();

map.put("html", MediaType.TEXT_HTML_TYPE);
map.put("xml", MediaType.APPLICATION_XML_TYPE);
map.put("json", MediaType.APPLICATION_JSON_TYPE);

return map;
}

public Set>getProviderClasses() {
Set> rrcs = new HashSet>();
rrcs.add(ProductProvider.class);
rrcs.add(OrderNotFoundProvider.class);

return rrcs;
}
}


The Restlet OrderApplication class from my earlier example has now transformed to an instance of JaxRsApplication to which it attaches the above mentioned OrderConfig class:

public class OrderApplication extends JaxRsApplication {

/**
* Class Constructor. Attaches the {@link OrderConfig} class.
*
* @param context Restlet Context
*/
public OrderApplication(Context context) {
super(context);
attach(new OrderConfig());
}
}


One issue we need to address is how will resource classes, Mapper Beans, Services etc get Autowired and injected, i.e., where is the Spring Hook? The JaxRsApplication class supports the concept of Custom Resource creation factories. This hook is utilized by creating a Custom Spring ObjectFactory that instantiates and provides Spring Managed bean. Setting the hook into the JaxRsApplication is achieved using a Custom Restlet ServerServlet as shown below:


public class SpringServlet extends ServerServlet {


public Application createApplication(Context context) {
JaxRsApplication application = (JaxRsApplication) super.createApplication(context);

// Set the Object Factory to Spring Object Factory
application.setObjectFactory(new SpringObjectFactory(getWebApplicationContext()
.getAutowireCapableBeanFactory()));

return application;
}

private static class SpringObjectFactory implements ObjectFactory {
private final AutowireCapableBeanFactory beanFactory;

public SpringObjectFactory(AutowireCapableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}

public T getInstance(Class jaxRsClass) throws InstantiateException {

@SuppressWarnings("unchecked")
T object = (T) beanFactory.createBean(jaxRsClass,
AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT, false);

return object;
}
}

public WebApplicationContext getWebApplicationContext() {
return WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
}
}

I could not use the Restlet's SpringServerServlet for the implementation as it expects a RestletResource and Router etc.

Thoughts on JSR 311 and JAXRS and forward:

I quite like the JSR 311 method of creating the Web Service. I found the clean separation of Providers and Resources via annotations really helpful. The use of annotation makes reading the Resource code very simple and the Resource code itself is not working with Representation's like before. I would like to introduce WADL and WADL2JAVA into the example at some point. I also would like to see better JSON support. In addition, I am curious as how other implementations of JAXRS work and in particular provide for easy integration with my favorite framework Spring. One thing is the lack of a Client API from the specification that I regret.

Enviorment on which example was run:

OS - Windows Vista, JDK-1.6.X, Maven 2.0.8.

The JAXRS, Spring, Maven, Dozer example can be downloaded from HERE.

If you are unable to run the example, as always Ping me and I will be glad to help if I can :-)

Friday, April 25, 2008

REST Web Service Example with Restlet, Spring and Maven...

Time for me to blog something of technical interest again. Ever since I have
joined Overstock.com, I have found myself working with two new technologies, REST and
MAVEN. By no means do I consider myself an expert on the same but feel that
sharing some of my experience might prove beneficial to someone else.

A Restlet 2.0 Example is available in a later POST I would however recommend a read of this one before proceeding to the 2.0 example.

Clearly, I cannot share any OSTK proprietary work...

First some words about Maven. I have always wanted to use Maven even during
my career at PRFT. Sadly, I didn't get to it. Maven is not another ANT, it
so much more. Ever since I have started using Maven, I cannot find myself
not using it when possible.

Noting a few maven terms (some coined by me others maybe not ;-)):

1. Maven Repository:

A Maven repository is a public/private site that hosts different libraries
or jars.

2. Artifact Coordinates:

Every jar in a Maven repository can be identified by coordinates. For example,
if one is trying to find spring-2.5.1.jar, the artifact is represented as:

<groupid>org.springframework</groupid>
<artifactid>spring</artifactid>
<version>2.5.1</version>


Think of group Id as being a top level folder that aggregates multiple artifact
types. An artifact Id describes a particular artifact in the group and the
version helps identify the version of the artifact.

3. Local Repository:

Maven downloads artifacts and places them in your $HOME/.m2 folder. Thus, you
always maintain a copy of the jar, i.e., a nicely shelved away via version. Thus the jar will not
be downloaded all the time but only once.

4. POM:

The foundation of maven lies in what is known as a POM or
Project Object Module. When using Maven, you will often find files titled
pom.xml. These pom files describe your project for you. A Maven project
can serve as an 'Aggregator' project that serves to group children project
under one umbrella. These project are typically called "Multi-Module" projects.

5. Maven Eclipse Plugin:

I use the Q4E Maven Eclipse plugin. Its pretty nice but not yet perfect. With the plugin, I am able to import the different maven projects into eclipse. The visual dependency management feature of this plugin is awesome.

6. Maven Archetype:

An Archetype is a template for creating projects in its likeness. There are different archetype available, for example an archetype to create a J2EE EAR project, a Web Project, a simple java project and App fuse projects as well.

Enough about Maven, a bit about REST!

I am not planning on entering into a REST versus SOAP or what is REST
discussion here but merely wanting to demonstrate a Web Service that uses
REST and Maven.

The stir created by Roy Fieldings dissertation has opened multiple discussions
and thoughts regarding how the Web should be viewed.

An implementation of REST concepts in Java was facilitated by the RESTLET project pioneered by Jérome Louvel.

One of the core classes of the RESTLET framework is the Resource class. Resources tend to represent exactly what their name means, a resource! For example, an Order Resource that
represents Order related data, a Product Resource that represents Product
information etc. I would like to talk more about REST and the RESTLET project
but the posting would be too verbose...maybe a later post.. One can get a good understanding of the RESTLET project via their documentation and starter examples.

Onto the example:

The example demonstrates a simple Restful Web service developed
using Restlet + Spring Framework + JaxB + JSON + Maven + Dozer + JUnit + EasyMock.

The project is organized as follows:


SpringTest
.
-- client

-- common

-- integration-test

-- service

`-- webapp


1. Spring Test:
The Web Service project is a multi module Maven Project. The SpringTest project
is the root level aggregator project that aggregates the modules such
as common, client, service, integration-test and webapp.

2. common:

The common project contains the code that is shared by other modules
of the web service project. It contains the DTO (data transfer objects), common
exceptions, utilities etc.

3. client:

The client project represents the Webservice client code. This project is
pretty much a wrapper around the Restlet API so that consumers of the service
have an easy way to communicate with the web service without having to
concern themselves with specifics of the web service.

4. service:

The service project represents the heart of the web service. The
service is not mixed in with the webapp project as the business logic is
not necessarily tied to RESTLET or REST. If required in the future, a
SOAP or EJB version of the web service could be exposed by re-using the code
from the service project.

The domain model is included in the service project itself. The reason for
the same is; in many cases the model and the service go hand in hand. Now, it
could be argued that the model could be placed in a separate maven module for
re-use. That IMO should be the direction should the model appear to be
re-usable. Also note that the model need not necessarily translate to what
is transferred via the web service. I am therefore making a separation of the
model and the DTO. There is clearly no one size fits all here and depending
on the scope of the project, making the model and the DTO one and the same
might be an option.

5. integration-test:

The project contains a test which will perform end to end integration test.
When an integration test is run, a Jetty Server instance is started using
Cargo and the webapp is deployed onto the server. Then the integration test
is performed which will communicate with the server to assert that the
web service contract is valid and the server will ensure that it performs
as expected. My reason for using Cargo is that one could easily switch to a
different container for testing if required.

Note that one could have additional integration test projects defined when the service
undergoes an upgrade and there is a need to maintain backward compatibility with the Web Service clients.

What does the example do?
The example is a simple mock of an order system. One can get a list of
Products supported by using the Product Service. The Product Service
uses JSON for its transport (just to demonstrate). The Order Service
can place an order, update an order, query an order and delete and order.
The Order Service uses JAXB for marshaling its data.

Standard REST concepts like POST, PUT, GET and DELETE are explored by the
example. I don't believe that I have 100% conformity with REST concepts in the example :-)

The example is a 'simple' one in all senses of the word. Thread safety,
exceptions etc are not even considered. One could easily incorporate the
same if developing a real world web service.

The Project uses Spring as a DI container. Rest Resources are injected with
dependencies using Spring auto-wiring.

Running the example:

1. JDK 1.5.X or Greater:
Ensure you have jdk1.5.X+ installed. The code uses annotations extensively.
From your command line, when issuing a "java -version" make sure that
it is greater than or equals to 1.5.X.

2. Maven Install:

Download Maven and install it. If on a *Nix environment, install maven at
/opt/. Ensure that maven is available in your PATH. What this means is if
you execute a "mvn -version" you should see details of your installation. Additionally, ensure you obtain a 2.0.x version of maven.

3. Eclipse Install:

Download and install an eclipse distribution. Eclipse is not required to run the examples but helps in viewing editing the code.

4. Q4E Maven Plugin:

Open eclipse and install the Q4E Maven plugin. Note that you might need to point the plugin to your maven installation.

5. Download Example:

Download and extract the SpringTest.zip project using your favorite archiving tool. The example has been tested with Restlet 1.1-M4 and Java Version 1.5.X and 1.6.X. If you would like to use a version that uses the API's from Restlet 1.1-M2, then the same can be obtained from HERE.

6. Import into Eclipse:
Import the modules into eclipse as Maven projects. Again this step is optional. It is required if you would like to view the project.

7. Installing Modules:
From the command line, issue a "mvn install" from within the
SpringTest project. What this command does is installs the maven modules in your local repository. As part of the process it will execute JUnit tests and integration tests.

8. An Integration Test:

Run a "mvn integration-test" from the SpringTest folder to see the
integration test in action.

8. Debugging the Web App:
Alternatively, you can watch the project in action by starting jetty
from the webapp project and debugging via remote server attach.

You will need to start jetty from the webapp project using "mvn jetty:run" and then do a remote server attach from eclipse. Ken Steven's blog has a pretty nice description as to how to do the same.

If you have difficulties executing the project, ping me...;-).. Once again the code for the example is available HERE.

The very same example that uses JAXRS (JSR 311) is described HERE.