Random bits of information by a developer

Showing posts with label seam catch. Show all posts
Showing posts with label seam catch. Show all posts

08 December 2010

Seam Catch Alpha2

Over the weekend Seam Catch Alpha2 was released! I'm trying to do a two week timebox release cycle for Seam Catch. Alpha 2 contains some minor API changes (some additions, and a couple of renames), a new qualifier and a couple of new objects for better framework integration. The largest of these enhancements is the ability to support ServiceHandlers.

Qualifier changes

The @HandlesExceptions is no longer a qualifier, this was needed to support ServiceHandlers, and is simply a marker anyway. This shouldn't affect users.

We've added a new qualifier @CatchResource to help distinguish resources injected into handlers that are only for Catch use. Here's an example:

public void logToSpecialCatchLog(@Handles CaughtException<Throwable> e, @CatchResource Logger log)
{
    log.warn("Unexpected exception caught: " + e.getException().getMessage());
}
      
It doesn't do much, but this shows that the Logger instance being injected is a special log configured only for Catch. This qualifier can be applied to anything and helps the developer visually see what resources are really being used.

ServiceHandlers

This feature is a great feature that really makes exception handling easy. So far we've seen examples of creating handlers with full method implementations, if you're doing something specialized, but repetitive, such as a JAX-RS error response you end up writing the boiler plate code over and over again just to change a few things (the message and the status code). Now you can do this sort of thing with only writing the boiler plate part once, the rest is all declarative, take a look!
@HandlesExceptions
@ExceptionResponseService
public interface DeclarativeRestExceptionHandlers
{           
   @SendHttpResponse(status = 404, message = "Requested resource does not exist")
   void onNoResult(@Handles @RestRequest CaughtException<NoResultException> e);

   @SendHttpResponse(status = 403, message = "Access to resource denied (Annotation-configured response)")
   void onNoAccess(@Handles @RestRequest CaughtException<AccessControlException> e);

   @SendHttpResponse(status = 400, message = "Invalid identifier (Annotation-configured response)")
   void onInvalidIdentifier(@Handles @RestRequest CaughtException<IllegalArgumentException> e);
}
      
There are three handlers right there, nothing else (save the [ServiceHandler][] implemenation) is needed! These handlers all send an error response for a JAX-RS request. They all change the status code returned and the message. What does it take to implement this? Aside from the new annotation (@SendHttpResponse), there's two other classes that need to be written:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@ServiceHandler(ExceptionResponseServiceHandler.class)
public @interface ExceptionResponseService
{               
} 

public class ExceptionResponseServiceHandler
{
   @Inject @CatchResource
   private Instance<ResponseBuilder> builderProvider;

   @AroundInvoke
   public Object processException(InvocationContext ctx)
   {
      Method m = ctx.getMethod();
      if (ctx.getParameters().length > 0 && ctx.getParameters()[0] instanceof CaughtException)
      {
         ResponseBuilder builder = builderProvider.get();
         CaughtException<?> c = (CaughtException<?>) ctx.getParameters()[0];
         if (m.isAnnotationPresent(SendHttpResponse.class))
         {
            SendHttpResponse r = m.getAnnotation(SendHttpResponse.class);
            String message = r.message();
            if (r.message().length() == 0 && r.passthru())
            {
               message = c.getException().getMessage();
            }

            builder.status(r.status());
            if (message != null && message.length() > 0)
            {
               builder.entity(new ErrorMessageWrapper(message));
            }
         }
         else
         {
            builder.entity(new ErrorMessageWrapper("Unknown error"));
         }
      }
      return Void.TYPE;
   }
}
Most of this is building up the error from the annotation, but it's only 26 LoC, and you quite a bit of reuse from them. That's all there is to it! Framework integrations should implement some of these for basic things, but you can further create them for yourself if you have some repetitive action that you can extract in your exception handling practices. Look for another release (Alpha3) in a couple of weeks and a Beta out by the end of the year!

24 November 2010

Seam Catch Release

Seam Catch Alpha1 was released yesterday! You can read about ithere, or the docs. Bits can be found in the JBossrepository using maven:
<dependency>
    <groupId>org.jboss.seam.catch</groupId>
    <artifactId>seam-catch-api</groupId>
    <version>3.0.0.Alpha1</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.jboss.seam.catch</groupId>
    <artifactId>seam-catch-impl</groupId>
    <version>3.0.0.Alpha1</version>
    <scope>runtime</scope>
</dependency>
Or at SourceForge. I'm very interested in any feedback that you may have.

What is Catch?

Catch is the exception handling infrastructure in Seam3. I like to refer to it as Next Generation Exception Handling. It really goes beyond what was available in Seam2 and offers a complete solution for Exception Handling. It's built on top of CDI events so the entry point is very minimal and usage is quite easy.

Usage

For those who are familiar with CDI events, creating your own handlers will be very familiar. Handlers are quite similar to CDI Observers, though there are a few differences:
  1. handlers must be contained in a bean marked by @HandlesExceptions
  2. the first parameter in the method must be annotated with @Handles and be an instance of CaughtException&lt;T extends Throwable>
  3. handlers are ordered before they're invoked
Keep those things in mind and the rest is very easy.

Creating a Handler

The docs really cover this very well, but here's a simple handler to get you started:
@HandlesExceptions
public class JsfHandlers {
    public void redirectingHandler(@Handles(precedence = -100) CaughtException<Throwable> event, NavigationHandler nav) {
        nav.handleNavigation(FacesContext.getCurrentInstance(), null, "/error.xhtml");
    }
}
NOTE: The best way to tie this handler into JSF is by adding a JSF to Catch bridge by creating an ExceptionHandler (this will be added to Catch in the next release, as a separate jar) to fire the ExceptionToCatchEvent.

There's not much there as you can see. We're saying this is a general handler (the CaughtException type is Throwable) and we want it run towards the end of the cause container traversal (precedence = -100). If you're not familiar with JSF, this is will navigate the user to the error page at the end of the exception handling. Of course this would require some extra JSF integration pieces to produce the NavigationHandler such as Seam Faces or Apache CODI, or your own producer. The NavigationHandler is injected via CDI, in fact, any additional parameters past the CaughtException param will be injected for you. Anything that you need for your exception handling, as long as CDI can create it, can be injected for you.

Entering Catch

Above I mentioned the ExceptionToCatchEvent. This event is all that's needed to start the handling process. Something as simple as
@Inject Event<ExceptionToCatchEvent> catchEvent;
...
try {
    your code
} catch (Exception e) {
    catchEvent.fire(new ExceptionToCatchEvent(e));
}
will get the ball rolling.

That's really all there is to it! I'm looking forward to any feedback you may have, and bugs if you find them. Bugs should be filled in JIRA. In the next release look for bridges for JSF, JAX-RS and others, and the ability to filter stack traces!