Search This Blog

Wednesday, August 26, 2009

Restlet 2.0 example using Spring, Maven, Annotations and a Custom Converter

Its been some time since I posted regarding REST. Restlet 2.0 is on its way, I figured its time I updated the example I had created some time ago to a Restlet 2.0 milestone release. If you are continuing to read this BLOG, I would recommend a read of the Restlet 1.1 BLOG I mentioned prior to reading this one. So whats new with Restlet 2.0? A read of the Resource API refactoring page is recommended. One of the major features that I liked about JAX-RS over the core Restlet API while working with the former is that it is annotation driven versus class driven. Automatic content negotiation and the calling of the appropriate method in your Server Resource class for different Content-Types is really best left to the container. A method intended to serve content should not have if/else blocks for different content, something one would need to do in Restlet 1.1. Restlet 2.0 seems to take the same into consideration by providing the "best of both worlds" There were major changes that occurred on Restlet version 1.2 that the team at Restlet decided to change the release to a 2.0. Further details of the change can be obtained at http://blog.noelios.com/2009/05/27/restlet-2-0-m3-released/ Restlet 2.0 has a major change in the way Resources are viewed. In particular a split into a ClientResource and a ServerResource. Details of the same can be viewed on the Restlet Resource API refactoring WIKI page. In addition, there has been a refactoring of certain core classes to different packages. I also noticed that the Restlet API and Restlet engine are shipped as a single jar org.restlet.jar. I could not find the com.neolios packages any more. Finally, there is a jse and j2ee edition of Restlet available. So, eager to try out the Restlet 2.0 annotations, I reworked my example to use Restlet 2.0 while simplifying the Spring integration present. Compared to my previous example, I have reduced my Spring applicationContext.xml to be more thinner by using a more annotated approach.
<context:component-scan base-package="com.welflex">
</context:component-scan>

<!--  Spring Application. Note there are no mapping of resources here -->
<bean id="application" class="org.restlet.Application">
  <property name="name" value="orderApplication"></property>
  <property name="root" ref="root" />
   <!-- Added to handle Exceptions centrally -->
  <property name="statusService" ref="applicationStatusService"/>
</bean>

<bean id="root" name="router" class="com.welflex.order.rest.SpringBeanRouter"/>
<bean id="beanMapper"
 class="net.sf.dozer.util.mapping.DozerBeanMapper">
  <property name="mappingFiles">
    <list>
 <value>dozerBeanMapping.xml</value>
    </list>
</property>
</bean>
The OrdersResource has changed to:
@Component(value = "/orders")
@Scope(value = BeanDefinition.SCOPE_PROTOTYPE)
public class OrdersResource extends ServerResource {
  ......
  @Post
  public JaxbRepresentation<OrderDTO> createOrder(Representation rep) {
    ...
    return new JaxbRepresentation<OrderDTO>(MediaType.APPLICATION_XML, dto);      
  }

}
Note that the OrderResource class now extends ServerResource unlike in my previous example which extended the Resource class. Also note that the mapping of the resources to paths are defined in the OrderResource class itself unlike in the xml file in my previous example. The POST method, called createOrder() accepts and returns XML. The return type is a JaxbRepresentation. If we desired, we could have another method in the code that accepts JSON content and returns JSON content that is titled createJSONRepresentation(). Depending on the content type requested, the appropriate method would be called. This is much better than having an if/else block in an acceptRepresentation(Variant v) method. Take a look at the Products Resource, that returns a JSON representation when a GET method is invoked. Note that this method will only return JSON content.
@Component(value = "/products")
@Scope(value = BeanDefinition.SCOPE_PROTOTYPE)
public class ProductsResource extends ServerResource {
  ......
  @Get
  public JsonRepresentation getProducts() {
   .....
   return new JsonRepresentation(jsonString);
  }
}
Pretty nice, I would say. To spoil the party, one of the things I liked about the JAXRS implementations was that I could annotate a Resource with the media type it supported and if it were a JAXB object it would automatically marshall the XML, if it were JSON, it would automatically marshal the same as well. The same can be accomplished in Restlet by using a Converter Service that converts a java object to and from a media type. There are plans for adding JAXB converters amongst others in 2.0 M5. In short, by using a Converter Service, I would like the createOrder() method to have the following signature, i.e., method returns a JAXB Object, however the container knows how to marshal that into XML back to the caller:
@Post("xml":"xml")
public OrderDTO createOrder(OrderDTO inOrder) { return outOrderDTO; }
So what about the ClientResource class? How does that work? Well with Restlet 2.0, one can continue to use the Restlet Client class or use the ClientResource class. The ClientResource is not thread safe. An example of how the ClientResource can be used is shown below in the OrderClientImpl class:
public class OrderClientImpl implements OrderClient {
  private static final String ORDERS_RESOURCE_URI = "/orders";
  private final String baseUri;

  public OrderClientImpl(String baseUri) { this.baseUri = baseUri; }

  public OrderDTO createOrder(OrderDTO order) throws IOException {

    ClientResource ordersResource = new ClientResource(baseUri + ORDERS_RESOURCE_URI);

    try {
      return ordersResource.post(order, OrderDTO.class);
    }
    catch (ResourceException e) {
      throw new IOException(e);
    }
  }

  public void updateOrder(OrderDTO order) throws OrderException {

    JaxbRepresentation<OrderDTO> orderCmd = new JaxbRepresentation<OrderDTO>(
        MediaType.APPLICATION_XML, order);

    ClientResource ordersResource = new ClientResource(baseUri + ORDERS_RESOURCE_URI + "/"
      + String.valueOf(order.getOrderId()));

    try {
      ordersResource.put(orderCmd);
    }
    catch (ResourceException e) {
      throw new OrderException("Order Update Failed", e);
    }
  }

  public OrderDTO getOrder(Long orderId) throws OrderNotFoundException, IOException { ....}
  }

  public void deleteOrder(Long orderId) throws OrderException {....}
}
I quite like the use of ClientResource versus the Restlet Client as I feel its more RESTful, i.e., talking to a Resource using HTTP verbs. However, again we witness the JAXB representation creeping in as we saw with the service due to the lack of a converter. I decided to create my own Converter for JAXB to see if I can get it to work and simplify the code base. One of the things I wanted to add just for my pleasure is a way to propagate server stack traces to the client. This is NOT what one would typically include in a representation of a resource as one would not want clients getting details of the working of a server, however, as this is my playground, anything goes ;-). After some tinkering, the following is my Jaxb Converter, it assumes that all JAXB root level objects have the annotation @XmlRootElement:
public class CustomXmlConverter extends XmlConverter {

  ......
  @Override
  public List<Class<?>> getObjectClasses(Variant source) {
    List<Class<?>> result = super.getObjectClasses(source);

    result = addObjectClass(result, JaxbRepresentation.class);
    result = addObjectClass(result, Object.class);

    return result;
  }

  @Override
  public List<VariantInfo> getVariants(Class<?> source) {
    List<VariantInfo> result = super.getVariants(source);

    if (source.getAnnotation(XmlRootElement.class) != null

      || source.isAssignableFrom(JaxbRepresentation.class)) {

      result = addVariant(result, VARIANT_APPLICATION_ALL_XML);
      result = addVariant(result, VARIANT_APPLICATION_XML);
      result = addVariant(result, VARIANT_TEXT_XML);
    }

    return result;
  }

  @SuppressWarnings("unchecked")
  @Override
  public <T> T toObject(Representation source, Class<T> target, UniformResource resource) throws IOException {    
    .....    
    if (target.getAnnotation(XmlRootElement.class) != null) {      
      return new JaxbRepresentation<T>(source, target).getObject();
    }

    throw new IllegalStateException("Should not have got here");
  }

  @Override
  public Representation toRepresentation(Object source, Variant target, UniformResource resource) throws IOException {

    Representation result = null;
    
    if (source.getClass().getAnnotation(XmlRootElement.class) != null) {
      result = new JaxbRepresentation<Object>(source);
    }
    else {
      result = super.toRepresentation(source, target, resource);
    }
    return result;
  }
  .....
}
Great, so we have a Converter, how do we make Restlet use this converter for XML. In my common maven module (shared between client and web), I define a file in META-INF/services/org.restlet.engine.converter.ConverterHelper, and in that file, I have a single entry defining my custom converter. Now when the client and service code use the common library, they will use the Custom Converter I have defined for JAXB. Thus, to illustrate the change, my new resources for Orders and Order are shown below:
@Component(value = "/orders")
@Scope(value = BeanDefinition.SCOPE_PROTOTYPE)
public class OrdersResource extends ServerResource { 
 ..... 
 @Post("xml")

  public OrderDTO createOrder(OrderDTO dto) {
     ....
     return createdOrderDto;
  }
  ...
}

@Component(value = "/orders/{id}")
@Scope(value = BeanDefinition.SCOPE_PROTOTYPE)
public class OrderResource extends ServerResource {

  @Put(value = "xml")
  public void updateOrder(OrderDTO orderDTO) {
    try {
      String id = (String) getRequest().getAttributes().get("id");

      orderDTO.setOrderId(Long.parseLong(id));
      persistOrder(orderDTO);
    }
    catch (RuntimeException e) {
      getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
      throw new OrderException("Failed to update an order", e);
    }
  }
 .....
}
We are no longer returning Representations in the above code. Quite similar to JAXRS, wouldn't you say ;-)? On the Client end, the OrderClientImpl no longer deals with Representations but only OrderDTOs as shown below:
public class OrderClientImpl implements OrderClient {
  ....
  public OrderDTO createOrder(OrderDTO order) throws OrderException {
    ClientResource ordersResource = new ClientResource(baseUri + ORDERS_RESOURCE_URI);

    try {
      return ordersResource.post(order, OrderDTO.class);
    }
    catch (ResourceException e) {
      throw new OrderException("Error Creating an Order", e);
    }
  }

  public void updateOrder(OrderDTO order) throws OrderException {
    ClientResource ordersResource = new ClientResource(baseUri + ORDERS_RESOURCE_URI + "/"
      + String.valueOf(order.getOrderId()));
    try {
      ordersResource.put(order);
    }
    catch (ResourceException e) {
      throw new OrderException("Order Update Failed", e);
    }
  }
}
I like the simplicity of the above and cannot wait to see the release of Restlet 2.0 that has the additional converters built in. For those interested, I have a maven project example available for download. The project provided uses the custom JAXB converter. To execute the project, one would need to use JDK1.6.X and maven 2.0.9 or higher. To view an integration test in action execute, "mvn install" from the root level of the project. The result should be something like:
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.welflex.order.IntegrationTest
log4j:WARN No appenders could be found for logger (com.welflex.client.ProductClientImpl).
log4j:WARN Please initialize the log4j system properly.
Aug 28, 2009 8:59:55 PM org.restlet.engine.http.StreamClientHelper start
INFO: Starting the HTTP client
20:59:55 DEBUG - com.welflex.order.rest.ProductsResource.getProducts(44) | Getting Products in JSON Format
Number of Available Products:3
Product Id:663123
Product Id:9912123
Storing the order...
Aug 28, 2009 8:59:55 PM org.restlet.engine.http.StreamClientHelper start
INFO: Starting the HTTP client
20:59:56 DEBUG - com.welflex.order.rest.OrdersResource.createOrder(45) | Call to post an order:..........
Updating the order...
Order successfully
Retrieving the order...
Deleting the order..
20:59:56 DEBUG - com.welflex.order.rest.OrderResource.getOrder(86) | Requested order with id:5499731937442305515
20:59:56 DEBUG - com.welflex.order.rest.ApplicationStatusService.getStatus(21) | In Order Status Service :class org.restlet.resource.ResourceException
Expected Order to not be found. Look at the server stack we got back
com.welflex.exception.OrderNotFoundException: Error obtaining Order
 at com.welflex.client.OrderClientImpl.getOrder(OrderClientImpl.java:60)
 at com.welflex.order.IntegrationTest.testLifeCycle(IntegrationTest.java:131)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
More on Restlet 2.0 once its released. For now, maybe I should probably look toward cleaning up the JaxbConverter and submitting it to Restlet or better still head in the search of kindred spirits, if you know what I mean ;-)

Tuesday, August 11, 2009

Documentating Software, my 2c

Documentation....Aaargh..why in heavens name would anyone waste time on it? The following few words are a window into my experiences and thoughts on documentation in IT organizations.

Sadly, most organizations cannot or will not afford, the luxury of an additional resource who is dedicated to just the task of documentation, i,e., a technical writer. So as developers and architects where does that leave us ? I have heard statements such as:
  • "Your code should be clear enough such that documenting the same is redundant"
  • "Documentation is not much value unless its kept up to date, bad or expired documentation is worse than no documentation"
  • "It is more important that the code has enough test coverage. The tests if good, document the code use"
  • "We do not have the time, it is lowest on our priority list. We got bigger fish to fry."
Don't get me wrong, I am not in total disagreement regarding the above. Neither am I a subject matter expert on documentation. I am someone who often finds myself in the middle of this.

What I find myself questioning is:
  • If the code is so self documenting or clear, and if you find people keep asking the same question over an over, is it really so self documenting ?
  • If one created documentation, clearly it was considered important. If important, then it would need to updated with the same love when created.
  • And please, there is always time...:-)
I have often entered an enterprise only to find that there is no Enterprise level documentation, stale or current. On the other hand, I have walked into an Enterprise only to be handed a thick set of pages to wade over to acclimatize myself. Neither worked for me, what I was seeking as an entrant was to see the enterprise from the 2000 feet level and then drill down as appropriate.

I am a very visual person, many a time a figure to me means more than a 1000 words. If there is a diagram that describes the stack the company uses, the applications, the services, even if partially wrong, immediately gives me a description of the architecture and/or project. That is a big win as far as acclimatising me to the environment.

When different folk ask the same question to me many times over, to me, that is another clearly indication of a lack of documentation. If a topic is constantly questioned, it deserves a place IMHO for documentation such that the next time the question arises, I point the person posing the question to the documentation instead of the repeated sermon that only I hold the copyrights to. DRY (Don't repeat yourself) does not apply to code alone...

Documentation is often created with great detail and appears as a big win, however if it starts becoming stale, then it loses its value and significance and becomes more of a "White Elephant". A conversation I had with someone in the past:

Someone: "Can you help me with this?"
Me: "Sure, did you check the documentation on the same?"
Someone: "Yeah but that is so outdated, so I don't bother looking at it any more"

The above conversation totally supports the argument that bad or documentation that are stale are definite deterrents to readers.

The following represent a few directions regarding documentation that I will try to adhere to:
  1. Enterprise or Project Documentation or "The BIG Picture documentation": From an Enterprise architect perspective, providing a high level description/diagram of the entire enterprise and how it all fits or works together can be valuable. The documentation does not have to drill into the microscopic details but instead provide a more a high level view that helps an entrant understand how all the parts of an enterprise fit together. From the perspective of a team lead/lead developer, it would be beneficial if documentation were provided regarding the boundaries and dependencies of a particular project. There is no need for details of a database schema, however there is need to indicate that the application talks to a particular schema on a particular database . These documents might even be able to help detect problems in the architecture, as now, you are looking at "The Big Picture" From previous experience, I also feel that documenting "Big" decisions that affect a project can have great value. With time, we tend to forget the reasons for choosing a direction. A place to consult back as to "Why?" can prove valuable.
  2. Stack Documentation: A diagram and/or description indicating the various technology stack in play. For example, "JBoss - App Server, Spring Framework, HP UX - 10.2 deployment OS, ..". This might be encompassed within the scope of point no.1. Again, stacks are rarely changed, and if they are, they probabaly require immediate attention.
  3. Repeated Query Documentation: If any question posed to a developer or architect is being asked more than once, regardless of its longevity deserves due diligence in the documentation space. In lawyer terms, it would classify as "Asked and answered" :-). If you enjoy the interaction and enjoy repeating the same answer, well then more power to you , please disregard the documentation angle.
  4. Redundant Documentation : Code that contains redundant or unnecessary documentation (i.e., code is self explanatory) serves no purpose. I violate this sometimes and need to stop. For example, getters and setter of a POJO (Plain Ole Java object) rarely requires documenting if the method name is clear. Institute naming standards that are enforced. Don't bother with class or schema diagrams, any developer worth his salt will be able to easily find free tools to reverse engineer classes or database schema's and be able to get the most current versions of the same.
  5. Documenting Complex Code: Code that is unavoidably complex, deserve either strong documentation or better still refactoring.
  6. Job security as it applies to documentation: Job security is not improved by keeping the details in your head. People are smart and folks that tend to do that will not last in a smart organization. Organizations lacking strong leaders, well get strong and smart leaders :-)
  7. When to document and how much ? : Things that are in constant flux are hard to document, wait for stabilization. However, do follow up after stabilization occurs. Make sure your code works first, then comes the documentation. If you have good documentation but code that is broken, thats not a win. In the same vein, I would go further to say, Unit Tests and Integration Tests are more valuable than documentation. Place yourself in the position of a person who will utilize the documentation, make the content detailed enough for your intended audience. For example, in an enterprise level document, do not bother listing individual Web Services or Database Schemas, it is enough to state that Web Services communicate with databases and or other Web Services. The detail in the documentation should also be only that much that you can afford to keep current moving forward. Finally piggy backing on this point, broken windows or no windows from the top can send a bad message. What I mean is, "If an architect or lead themselves do not document, then it becomes a hard sell to a developer that they need to document"
  8. Detail and Artistry of Documentation: Reiterating, "Make it right before making it pretty". A straw diagram caught on a white board via a cell phone camera during the design, if posted on a WIKI is often as effective as a colorful work of art. High ceremony documentation is almost too much and often unnecessary. Concise and to the point documentation works in most cases. People are smart, they often like a start. Its like being provided a map into Yellowstone regarding the sights to see. One does not require information on the concentration of sulfur at each site, just where the sites are located, we'll figure out the sulfur content at each site :-)
  9. Tools for documentation: Use a tool that works for collaborative authoring such as a WIKI. Almost any software development project IMO deserves a WIKI or equivalent presence. Media WIKI and such are free to use, so a smart person would avail such tools. Use technology where applicable.
  10. Collaborative Documentation: Documentation on IT projects should not belong to a single owner but be considered a collaborative effort. In other words, every member of the team should feel that they can add or correct toward the documentation. If a person comes asking a question and you give an answer, if you ask the person to document the same as you feels its valuable and is missing, you might be surprised as to how gladly they are willing to contribute. On the same note when you find documentation that is outdated and more importantly wrong, deprecate the documentation at the very top if you do not have the time to make it current.
  11. How to get started, documentation: As an entrant into a new IT environment, one often needs to get set up and be ready to get productive. A road map documentation that provides a user of "What, Why, Where, Who" can be quite useful.
  12. Selling documentation to the business: Getting business to account for time slots for code testing itself can be a daunting task in some organizations, getting a time slot in the project budget for documentation can be harder sale. However, as a lead or person making an estimate of a project, it is important to bake in the same. Documentation is money, however you need to sell the same and its value to the business. Lack of critical documentation is something that can come back to haunt you. "Protect your skin and those of your kinsmen" :-)
I am sure I have only touch the tip of what needs documentation. I cannot claim the title of a "Documentation nazi" and/or authority, neither am I claiming a "One set of rules fits all". People have probably written books on the same.....Easy to preach, hard to do, but hey, trying is not so hard, is it, and that is motive, trying ;-)...