Phil Webb's Blog

Random thoughts from a software developer

Logging a full stacktrace in Spring Web Flow using a FlowExecutionListener

leave a comment »

One problem I sometimes encounter when using Spring Web Flow is that the root cause of exceptions get burred so deep that they are not always logged.

For example, say you have an end-state that calls a bean method, and that method throws an exception:

<end-state id="finish">
    <output name="result" value="someBean.processFinalResultAndSometimesThrow()">
</end-state>

You will probably end up with a log entry like this:

org.springframework.webflow.engine.FlowOutputMappingException: Errors occurred during output mapping in state 'finish' of flow 'exampleFlow'; errors = [[SourceAccessError@3f3a3f3a mapping = someBean.processFinalResultAndSometimesThrow(), code = 'evaluationException', error = true, errorCause = org.springframework.binding.expression.EvaluationException: An ELException occurred getting the value for expression 'someBean.processFinalResultAndSometimesThrow()' on context [class org.springframework.webflow.engine.impl.RequestControlContextImpl], originalValue = [null], mappedValue = [null]]]

We get information about the flow and the state where the error occurred, we even get the bean method that was called, but we don’t have a complete stack trace of the actual root cause. Luckily for us the root cause is available and to log it you need to do is write a FlowExecutionListener:

import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.binding.mapping.MappingResult;
import org.springframework.stereotype.Component;
import org.springframework.webflow.engine.FlowAttributeMappingException;
import org.springframework.webflow.execution.FlowExecutionException;
import org.springframework.webflow.execution.FlowExecutionListenerAdapter;
import org.springframework.webflow.execution.RequestContext;

public class LoggingFlowExecutionListener extends FlowExecutionListenerAdapter {
    private final Log logger = LogFactory.getLog(getClass());

    @Override
    @SuppressWarnings("unchecked")
    public void exceptionThrown(RequestContext context, FlowExecutionException exception) {
        if (exception instanceof FlowAttributeMappingException) {
            List<MappingResult> errors = ((FlowAttributeMappingException)exception).getMappingResults().getErrorResults();
            for (MappingResult error : errors) {
                if (error.getErrorCause() != null) {
                    logger.warn("FlowAttributeMappingException thown containing error : " + error.getErrorCause(), error.getErrorCause());
                }
            }
        }
    }
}

Attach the listener in usual web flow way and all exceptions will be logged, complete with full stack trace.

Written by Phillip Webb

July 11, 2011 at 1:56 pm

Posted in Web Flow

Integrating Spring & JavaServer Faces : Dynamic Navigation

leave a comment »

Often your JSF application will need to move beyond basic static navigation and start to make dynamic navigation decisions.  For example, you may want to redirect users based on their age.  Most JSF tutorials recommend that dynamic navigation is implemented by binding the action attribute of a command to a backing bean:

<h:commandButton action="#{bean.actionBasedOnAge}"/>
public String actionBasedOnAge() {
  if(age &lt; 12) {
    return "fetchadult";
  } else {
    return "ok"
  }
}

The example above shows how anyone under twelve is directed to 'fetchadult' instead of the usual 'ok'. Both the 'fetchadult' and 'ok' outcomes will need to have navigation rules defined in the faces-config.xml so that JSF knows what actual page to display.

When working with Spring MVC it is often more natural to have navigation logic contained in the @Controller bean. To help with this, implicit 'controller' and 'handler' variables are available when rendering JSF from MVC. The 'controller' variable provides access to the controller bean that was mapped to the original request, and the 'handler' variable to the underling MVC handler.  In Spring 3.0 'controller' and 'handler' are generally the same object. In Spring 3.1 however, the underlying MVC architecture is changing and 'handler' will generally be a org.springframework.web.method.HandlerMethod instance.

Here is a submit button that references the someNavigation() method of the the @Controller:

<h:commandButton action="#{controller.someNavigation"/>

Whilst accessing the controller bean is useful, it is not the ideal solution.  I prefer to use logical names in my JSF pages and map those the Java methods.  I also want an easy way to get back to data from the underlying model.

The @NavigationMapping annotation provides another, more flexible approach to handling navigation.  It works in a very similar way to @RequestMappings.  The annotation can be placed on any public method in your @Controller to map navigation outcomes to destinations.

<h:commandButton action="submit"/>
@NavigationMapping
public String onSubmit() {
  return "redirect:http://www.springsource.org";
}

If you need access to a backing bean the standard Spring @Value annotation can be used.  Any EL expression that the page can resolve can also be used on a navigation method parameter.

@NavigationMapping
public String onSubmit(@Value("#{person.age}") int age) {
...
}

Accessing model elements is even easier.  As long as you only have a single object of the type you want to access in your model, and it is not a simple type (int, String, etc), you don’t need any annotations:

@NavigationMapping
public String onSubmit(Person p) {
...
}

Other argument types can also be used (see the JavaDoc for a complete list).  For example, here is a navigation mapping that handles 'submit', 'cancel' and 'save' outcomes.  The injected arguments tell us the which of the three outcomes was clicked and provides access to the source UIComponent.

@NavigationMapping('submit','cancel','save')
public String handleNavigation(String outcome, UIComponent source) {
...
}

Return types are also equally flexible.  You can return view names as Strings, you can also use the same "@hotelsController.show" notation that I have previously blogged about.  You can also return View objects directly or you can use NavigationOutcome if you want to include implicit model items.

Finally, if you just want to render an immediate response you can use the @ResponseBody annotation or return a HttpEntity.  This works in exactly the same way as Spring.

Written by Phillip Webb

July 1, 2011 at 7:56 pm

Integrating Spring & JavaServer Faces : MVC Nuts and Bolts

with 3 comments

I have attempted to integrate JSF with Spring MVC in the past, and whilst my first attempt worked, it was far from ideal.  This time around I decided to take a few key decisions to help focus my efforts:

  • Drop backwards compatibility.  There is just too much work involved with supporting JSF 1.2 and too much good stuff coming up in Spring 3.1 to ignore.
  • MVC annotations are king.  @RequestMapping seems to be the preferred approach for most people; lets only support this and keep any custom annotations to a minimum.
  • Reduce dependencies.  It’s nice to reuse stuff but this is an integration project so the less there is to integrate the better.

With this in mind I decided to take the org.springframework.faces.mvc.JsfView class from Web Flow as my inspiration.  This class works really well because it only deals with the View in MVC, the Model and Controller remain entirely in the realm of Spring.   The only problem with JsfView is the lack of postback support.  We need to somehow detect the difference between the initial request for a view and any subsequent JSF postback.

Thanks to Spring MVC having a very flexible architecture this is entirely possible.  We can have multiple HandlerMapping and HandlerAdapter beans registered with the DispatcherServlet.  To support JSF we need something high up in this chain that can detect and deal with  postbacks, leaving anything that is not a postback to be dealt with in the usual way.  Here is the general sequence of events:

user               dispatcher    @controller
 |  /some/request      |              |
 |-------------------->|   maps to    |
 |                     |------------->|  creates
 |                     |              |------------> FacesView
 |                     |                             (/pages/file.xhtml)
 |                     |   render                        |
 |                     |-------------------------------->|
 |                     |                           [Delegate to JSF]
 |  response           |<--------------------------------|
 |<--------------------|
 |                     |
 |                     |
 | /some/request       |
 | (postback)          |
 |-------------------->|      postback handler
 |                     |--------->|
 |                     |    [Delegate to JSF]
 |  response           |<---------|
 |<--------------------|          |
 |                     |          |

 
The postback handler has a couple of interesting problems to deal with.  1) How do we know we are a postback.  2) How do we know what view to restore.  Obviously a postback will be a HTTP POST operation, but we cannot blindly assume that all POSTs are JSF postbacks.  We also need to know what XHTML file to restore, but this file is based on a decision taken by the @Controller of the last request.

The answer to both these problems is to write our own JSF ResponseStateManager.  The ResponseStateManager is part of JSFs state management infrastructure and is responsible for reading and writing component state.  Usually JSF will save the state data in the HTTP session and write a hidden form field within the page so it can be restored later.  Hooking into this mechanism we can write an additional field for MVC, the presence of the field lets us know that we have a postback and furthermore the value will let us know what XHTML file to restore.

With the postback handler in place we now have the best of both the Spring and JSF worlds.  We can use @RequestMapping annotations to build expressive URLs and JSF components to render complex web pages.  If want to we can even return different Views for the same URL based on entirely different technologies (for example by inspecting the HTTP header we might decide to return a JSF page or a XML document).

If you want to look at postback handler code it is available here.  The usual caveats of this being a moving codebase apply.

Written by Phillip Webb

June 20, 2011 at 7:15 pm

Integrating Spring & JavaServer Faces : Navigation

with 2 comments

This is the first in what I hope will be a series of blogs about my efforts to provide deep integration between Spring and JavaServer Faces.  Everything mentioned here is a “work in progress” so if you checkout the code please be aware that it is a moving target; expect some rough edges and don’t be surprised if it’s sometimes broken.

You can already use Spring with JSF pretty happily out of the box, with Spring managing your beans and JSF handling your screens.  There is also some really great support for JSF in Spring Web Flow, if you are doing any flow based application you really should be using Web Flow.  Web Flow also provides the org.springframework.faces.mvc.JsfView class that will let you render a JSF page from Spring MVC.  Unfortunately JsfView only renders transient (stateless) views, if you want to handle postbacks you are out of luck.

Allowing Spring MVC to render JSF views that can handle postback has been my primary driver for starting this project.  Thanks to the flexibility of both MVC and JSF it is entirely possible to integrate these technologies (although the exact details of how are probably best saved for another post).  I want to spend the rest of this post talking about how we can create really nice JSF navigation.

If you have used standard JSF navigation you are probably used to the following type of thing in your faces-config.xml:

<navigation-rule>
    <from-view-id>/pages/list.xhtml</from-view-id>
    <navigation-case>
        <from-outcome>select</from-outcome>
        <to-view-id>/pages/details.xhtml</to-view-id>
        <redirect/>
    </navigation-case>
</navigation-rule>

Whilst it is pretty easy to understand, there are some obvious drawbacks of the standard approach, for starters its pretty verbose.  Most of the time I want to redirect my users rather than leaving them confused as to why the URL shows something different to their current page.  Needing that <redirect/> on virtually every element is really annoying.  The amount of XML obviously upset the developers of JSF themselves, and luckily JSF 2.0 has introduced the concept of implicit navigation. This is something we will make use of later.  If you want to read a really good article about JSF navigation checkout Fluent Navigation in JSF 2 by Dan Allen.

Navigation is really all about destinations, there is not much point in redirecting someone to a 404 page not found error.  Creating nice readable URL destinations has always been a bit of a struggle for JSF.  Right now, without developing your own code, the best option for creating readable URLs is probably to use PrettyFaces.  Of course, with JSF and Spring integrated nicely you don’t need to use anything other than the @RequestMapping annotation to create readable URLs. The example below shows a how you can map a nice readable URL to show hotel details from an ID.

@Controller
public class HotelsController {
  @RequestMapping(value = "/hotels/{id}", method = RequestMethod.GET)
  public String show(@PathVariable Long id, Model model) {
    model.addAttribute(bookingService.findHotelById(id));
    return "hotels/show";
  }
}

With @RequestMapping annotations in place we can think again about the navigation.  Usually the <h:commandButton>, <h:button>, <h:commandLink> or <h:link> components will be used to trigger navigation, for example:

<h:commandButton value="Go" action="select">

Here when the user clicks on the "Go" button the "select" action kicks in and the navigation rules are used to find a destination.  As we want to move away from defining navigation XML we need an alternative approach to find MVC destinations.  Slightly subverting JSFs support for implicit navigation gives us quite a nice way to do this.  With a bit of integration code we can support a special "spring:" prefix that tells JSF to resolve destinations using Spring MVC.

<h:commandButton value="Go" action="spring:redirect:/spring/hotels/123"/>

The example above will resolve "redirect:/spring/hotel/123" using the ViewResolvers registered with Spring MVC.  In this case UrlBasedViewResolver will pick up "redirect:" and a RedirectView will be used.

That’s quite nice, but hard-coding the hotel ID "123" into the view name is not all that practical.  Luckily there is an answer:

<h:commandButton value="Go" action="spring:redirect:/spring/hotels/{id}">
    <f:param name="id" value="#{resultItem.id}/>
</h:commandButton>

All <f:param> child tags of the commandButton will be used to construct a model for the MVC view.  In this case we get a model containing “id=#{resultItem.id}“.  The EL value expression #{resultItem.id} will be resolved before the view is rendered.  The RedirectView class in Spring 3.1 will deal with URL template variables, so “/spring/hotels/{id}” will pick up “id” to render the complete URL.

One slight irritation with the above method is that you need to define your URLs inside your XHTML files as well as in your @RequestMapping annotations.  As an alternative to this you can use a special “@bean.method” notation to indicate that you want to navigate to the value of the @RequestMapping on the specified controller bean method:

<h:commandButton value="Go" action="spring:@hotelsController.show">
    <f:param name="id" value="#{resultItem.id}/>
</h:commandButton>

If you have more than one @RequestMapping method on your controller bean you can navigate between them using the even shorter syntax “@method” (here the bean is assumed to be the current handler).  Of course not every type of @RequestMapping can be reversed into a URL, for example if you use wildcards then this will not work.  The advice is to keep your mappings as simple as possible.

One final benefit of this method is that we can also reverse the DataBinder process.  For example:

public class SearchCriteria implements Serializable {
  private String searchString;
  private int page;
  // ... getters / setters
}
@RequestMapping(value = "/hotels")
public String list(SearchCriteria criteria, Model model) {
  // ...
}
<h:link outcome="spring:@list">
    <f:param name="sc" value="#{searchCriteria}"/>
</h:link>

Assuming the #{searchCriteria} EL expression resolves to a SearchCriteria object containing the string "California" and the integer 10 the URL built would be "/spring/hotels?searchString=California&page=10".

If you would like to have a look at code for this project it is currently available at http://github.com/philwebb/springfaces.  As mentioned at the top of the post this code is a work in progress so please expect some problems.  My next task on the roadmap is to support a @NavigationMapping annotation that will allow programmatic navigation.

Written by Phillip Webb

June 18, 2011 at 11:48 pm