Search This Blog

Saturday, October 31, 2009

Ubuntu Karmic and Windows 7

Did two upgrades this weekend. Upgraded a laptop from Vista to Windows 7 and a desktop from Ubuntu Jaunty to Karmic, both 64 bit. Pleased with both upgrades so far. Vista was one of MS biggest lows as far as their OS version goes, Windows 7 seems more peppier in general so far.

I have been very pleased with Ubuntu ever since I installed the same. Have previously been a user of Mandriva, Fedora and Suse. Found mandriva comprehensive in its software offering but not very stable. I feel that Suse may be great to compete with Redhat on the server market but is no where as user friendly as Ubuntu. What I like about Ubuntu is that its pretty solid, convenient and just so easy to use. It detects the need for propriety drivers and installs in a breeze. Have dual monitor support without any xorg.conf tweaking. Printer, web cam all worked out of the box. Have it now running Skype as well without a problem.

After installing Ubuntu, I followed the following BLOG on a TODO list that really helped.
Anyway, got rid of the standard 1948 created Gnome menu in favour of AWN and now my desktop rocks.

A note for those installing eclipse 64 bit. One will find that clicking on some buttons does not work and one has use the keyboard actions to activate the buttons. The way around this problem is to set the following "export GDK_NATIVE_WINDOWS=true" prior to launching eclipse.

On the Windows 7 front, I prefer using Chrome over firefox or IE as its so much more faster on many sites that I frequent. The upgrade from Dell from Vista to Win 7 was pretty simple. Cannot watch youtube on 64 bit IE yet due to 64 flash plugin not available (no so on my Ubuntu though :-)) Don't get me wrong, I don't have anything against Win 7 (except $$$) but when compared with what FREE brings, I find it difficult to justify the extra $$$. I however do need to a Win machine due to the fact that there is no software for the iphone of any value on Linux and that there are sites that I go to such as CWTV to watch videos requiring Win or Mac. Another seller for the Win 7 is my few PC games that I have. BTW, I did not buy Win 7, its a free upgrade option.

The Mrs also is happy with Ubuntu...and as long as she is happy, I am as well :-)

Friday, October 16, 2009

Exceptions in RESTful HTTP with Restlet and JAXB

REST, or rather, RESTful HTTP and how exceptions can be handled therein is what this posting is about.

For those of us who have worked with SOAP and faults, we are familiar with how exceptions are handled. SOAP Stacks upon encountering an exception will throw a SOAP fault which is then marshalled into an exception on the consumer end of the service. SOAP faults in a way provide a protocol over standard HTTP.

When working with REST we have the concept of Resources and their Representations. An exception in a RESTful architecture is really a tuple of an HTTP Status Code and a Representation that describes the same.

The HTTP Status code in themselves are quite indicative, delving a bit into the same:
  • 1XX Series - Informational - Request received and continuing processing
  • 2XX Success - Action received, understood and accepted
  • 3XX Redirection - Further action required to complete the request
  • 4XX Client Error - Request is badly formatter or the server cannot process the request
  • 5XX Server Error - Server failure on a a potentially valid request
When working with architectures that have Java on both ends of a Service, shying away from Exception handling is IMHO a self imposed handicap. In a RESTful system, one would typically have an expected representation of a resource and in the event of exceptions, have them represented as alternate results along with the appropriate error codes. The JAX-RS specification has the concept of a WebServiceException.

What I am trying to do in this BLOG is a demonstrate how exception handling can be accomplished with a framework like Restlet. I am not demonstrating a specification by any means or a wrapper protocol. For the sake of this demonstration, I will be using Restlet and JAXB. In particular, the example will rely on the XmlAdapters of JAXB extensively coupled with the Java Reflection API and Annotations. The XmlAdapters serve to translate to and from Exceptions to JAXB Representions

The scope of this example is as follows:

a. Exceptions supported are of a particular type and its subclasses only:
Exceptions are restricted to WebServiceException and its sub classes. In addition, the WebServiceException is a RuntimeException. No checked exceptions. Any exceptions thrown by a Restlet Resource that are not an instance of WebServiceException will be converted to the same prior to being marshalled. Any WebServiceException marshalled, must have a JAXB Object associated with it.


@XmlJavaTypeAdapter(WebServiceExceptionAdapter.class)
public class WebServiceException extends RuntimeException {
// Http Status code
private int status;
}


// This class extends WebServiceException but has the same body as
// WebServiceException. For this reason, there is no special XmlAdapter required.
public class OrderException extends WebServiceException {
..
}

b. XML as the media type for Transferring Exceptions:
XML is the sole media type supported for exceptions in this example. Note that it is quite trivial to change the same to accommodate additional media types like JSON etc if required. Every Exception's representation is wrapped around with a WebServiceExceptionWrapperDto. The same is to allow for sub typing. Note that the targetException will be marshalled by an appropriate XmlAdapter at Runtime.

@XmlType(name = "ExceptionWrapper", propOrder = { "targetException" })
@XmlRootElement
public class WebServiceExceptionWrapperDto<E extends WebServiceException> {
@XmlElement(name = "targetException", required = true)
public E targetException;
}

c. Rich Exceptions:
Exceptions that can be richer, i.e., more than just message, cause and stack. For example validation messages, codes, inner objects etc. A simple example of the same is shown below where the OrderValidationException contains a description and a custom validation error code. The same could easily have been a complex object if required:


@XmlJavaTypeAdapter(OrderValidationExceptionAdapter.class)
public class OrderValidationException extends WebServiceException {
// A code representing the error
private int validationCode;

// A description indicating the cause of the validation error
private String validationMessage;
...
}


// Note that the OrderValidationException Adapter is behaving like a Template method pattern
// Base marshalling to an exception is handled by the parent class with the child only providing
// specific additions. The methods marshall() and unmarshall() are implemented in the parent class
// and will populate the base properties of the Exception and representation accordingly
public class OrderValidationExceptionAdapter extends
AbstractExceptionXmlAdapter<OrderValidationExceptionDto,OrderValidationException> {

@Override
public OrderValidationException toException(OrderValidationException created,
OrderValidationExceptionDto dto) throws Exception {

created.setValidationCode(dto.validationCode);
created.setValidationMessage(dto.validationMessage);
return created;
}

@Override
public OrderValidationExceptionDto toRepresentation(OrderValidationExceptionDto created,
OrderValidationException t) throws Exception {

created.validationCode = t.getValidationCode();
created.validationMessage = t.getValidationMessage();
return created;
}

d. Control over which parts of an Exception are marshalled:
Provide server stack, cause and message to client. At the same time, ability to prevent certain exceptions from transmitting stack. One might or might not want to marshall server stack in certain cases. The same will be accomplished via an annotation that resides on an Exception thrown. Note that the same can be enhanced for further control. In the example shown below, throwing of the BarException will not result in the marshalling of the stack or cause:

/**
* Foo Exception when thrown should not include server stack and any cause
*/
@ExceptionMarshallingParams(includeStack=false, marshallCause=false)
public class BarException extends WebServiceException {
}


e. Simple mechanism to throw exceptions on the Client:
Clients are aware of the Exceptions that can be expected from a Service and can expect them to be thrown appropriately. For example:

public OrderDto createOrder(OrderDto order) throws OrderValidationException, OrderException {
JaxbRepresentation<OrderDto> orderRep = new JaxbRepresentation<OrderDto>(order);
Response response = client.post(baseUri + ORDERS_RESOURCE_URI, orderRep);
if (response.getStatus().isSuccess()) {
orderRep = new JaxbRepresentation<OrderDto>(response.getEntity(), OrderDto.class);
try {
return orderRep.getObject();
}
catch (IOException e) {
throw new OrderException(e.getMessage(), e, response.getStatus());
}
}

// Not a Response we expected..throw one of the following exceptions expected instead
throw ExceptionUtil
.getWebServiceException(response.getEntity(), OrderValidationException.class, OrderException.class);
}


public class ExceptionUtil {
...
public static WebServiceException getWebServiceException(Representation xmlRep,
Class... expectedExceptions) {
StringBuilder packages = new StringBuilder(20);
packages.append(WebServiceException.class.getPackage().getName());

for (Class clazz : expectedExceptions) {
String ctxPath = getContextPath(clazz);
packages.append(":").append(ctxPath);
}

JaxbRepresentation<WebServiceExceptionWrapperDto<WebServiceException>> wsRep
= new JaxbRepresentation<WebServiceExceptionWrapperDto<WebServiceException>>(
xmlRep, packages.toString());
try {
return wsRep.getObject().targetException;
}
catch (IOException e) {
throw new RuntimeException("Error unmarshalling exception", e);
}
}
...
}

Note that it would have been nice if we could specify the exceptions that a method could throw using generics. That feature however is restricted to a single exception type and thus accommodating checked exceptions are hard.

f. Resource Classes throw Exceptions on failed code states:
Resource classes will be able to throw any type of WebServiceException and have it marshalled to the client. The Resource classes must however ensure they populate the Exception with the appropriate Http Status Code. For example, an OrderResource on create might throw an OrderNotValidException or an OrderException when a POST operation is invoked on it. At the same time, a GET on the OrderResource might throw a OrderNotFoundException.

public class OrderResource extends ServerResource {
@Post("xml")
public OrderDto createOrder(OrderDto dto) {
try {
dto = persistOrder(dto);
setStatus(Status.SUCCESS_CREATED);
return dto;
} catch (OrderValidationException ove) {
ove.setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
throw ove;
}
catch (OrderException e) {
getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
throw e;
}
}
@Get("xml")
public OrderDto getOrder() {
....
Order order = null;
try {
order = orderService.getOrder(orderId);
}
catch (OrderNotFoundException nfe) {
nfe.setStatus(Status.CLIENT_ERROR_NOT_FOUND);
throw nfe;
}
return (OrderDto) beanMapper.map(order, OrderDto.class);
}
....
}


public class HealthResource extends ServerResource {
private static int counter = 0;
@Get
public String isHealthy() {
// Simply to prove a point....
switch (counter) {
case 0:
counter++;
// Throw a WebServiceException
throw new WebServiceException("System is unhealthy", Status.CLIENT_ERROR_UNAUTHORIZED);

case 1:
counter++;
// throw a RuntimeExeception..this will be transparently marshalled
throw new RuntimeException("Some unexpected exception thrown as a Runtime");
}

getResponse().setStatus(Status.SUCCESS_OK);
return "OK YEAH!";
}
}

g. Marshalling of exceptions occurs via a Restlet Status Service:

A custom extension of the Restlet Status Service is responsible for marshalling all thrown Exceptions. The same is shown below:

public class JaxbExceptionStatusService extends StatusService {
....
public Status getStatus(Throwable throwable, Request request, Response response) {
Throwable cause = throwable.getCause();
WebServiceException exception;
String contextPath = ExceptionUtil.BASE_EXCEPTION_PACKAGE;

if (cause == null || !(cause instanceof WebServiceException)) {
// If not a WebService Exception then throw a WebService Exception
exception = new WebServiceException(..., Status.SERVER_ERROR_INTERNAL);
} else {
exception = (WebServiceException) cause;
String clazzContext = ExceptionUtil.getContextPath(cause.getClass());

if (!contextPath.equals(cause.getClass().getPackage().getName())
&& !clazzContext.equals(contextPath)) {
contextPath = contextPath + ":" + clazzContext;
}

if (exception.getStatus() == 0) {
exception.setStatus(Status.SERVER_ERROR_INTERNAL);
}
}

// Create the Exception Wrapper
WebServiceExceptionWrapperDto<WebServiceException> exceptionWrapper = new WebServiceExceptionWrapperDto<WebServiceException>();
exceptionWrapper.targetException = exception;

JaxbRepresentation<WebServiceExceptionWrapperDto<?>> rep = new JaxbRepresentation<WebServiceExceptionWrapperDto<?>>(
exceptionWrapper);

rep.setContextPath(contextPath);
response.setEntity(rep);
return Status.valueOf(exception.getStatus());
}
}

I have included herewith a Maven example that will demonstrate the client, service and exception management in use. The maven module titled "exceptionnmodule" contains the exception handling code. The integration will demonstrate different exceptions that are thrown by the server and re-thrown by the client code. In particular, you can see the the following abilities of the framework:

a. Ability to throw a simple RuntimeException from the Service and see it marshalled/unmarshalled as WebServiceException
b. Ability to throw an instance of WebServiceException
c. Ability to throw an exception that is a subtype of WebServiceException but without any addition body. For example, the OrderException.
d. Ability to throw a sub type of the WebServiceException that has additional body elements. For example, OrderValidationException.

One can witness the server stack, cause, HTTP Status, specific exception types. Simply run a "mvn install" from the top level project.

Although the example uses Restlet 2.0, the framework has no dependencies on the same. There might be many areas for improvement in the concept and I would like to hear about them if a reader of this blog has ideas. Also, in this example, I have used code from a posting by Ian Robertson on Artima regarding Reflecting Generics.

Finally, I don't know how this BLOG will format. I am trying something new, I hope it woiks!

Download the Code HERE!