The Source for Java Technology Collaboration
User: Password:



Jacob Hookom

Jacob Hookom's Blog

The New Servlet for MVC Frameworks

Posted by jhook on March 16, 2006 at 11:44 PM | Comments (2)

Frameworks of Today

All MVC frameworks basically operate within the same 5 phases:

  1. Decode Interpreting state/parameters passed from the client
  2. Validate This involves validating the information decoded and possibly authorization/authentication
  3. Update Once the submitted information is validated, update the Java model
  4. Invoke Some controller behavior is handled here, such as an action once state is applied from the update phase.
  5. Encode Rendering the result of the action invocation and model state back to the client

Each of our favorite frameworks are implemented differently, but these phases always exist in some form or as an optional phase. Look at Struts w/ ActionForms and Actions or the hook methods and interceptors within WebWork.

Historically, all of these frameworks start their integration with an HttpServlet or Filter. This is their platform:

public void service(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {
    // start here
}

Wow, thanks JEE. You can begin to see why there's so much redundancy or one off approaches to MVC implementations.

A while back, Kito Mann started a WebTier Alignment Group of framework developers. While the group unfortunately never really took off, there were some great discussions and comments. The group did identify that there's common artifacts and points of integration between these frameworks. Maybe a common way of defining validators or converters-- or even a common way of integrating a project's domain model?

I'm going to go out on a limb and suggest that frameworks instead piggy back on the FacesServlet. I'm not saying that framework developers use JSF as end developers do, but being that it's part of the JEE 5 specification, use the bits and pieces you need. There's so much there that can be provided to frameworks that operate completely different.

Frameworks of Tomorrow

To elaborate on this, I'm going to template out a simple Action framework that sits on top of JSF, but only uses a little bit of the features, not including the overhead of stateful components. Ideally, we want to process URIs like this:

/order.addItem.do?item.id=41667&item.qty=3&item.code=SA

First, based on our familiarity with the HttpServlet, where do we start with our simple solution for JSF? The easiest route is to implement a PhaseListener which intercepts requests and does all the processing itself. Alternately we can look at simply providing a Lifecycle implementation.

Because we want to provide RoR/WebWork-like features, it would be great if we can simply invoke or set properties directly on our domain objects from an IoC container. Well, the Faces API has a scoped IoC container built in and has integration from both Spring and JBoss Seam to name a few. Sounds like we're already ahead of the game for our simple Action framework.

To implement our request processing, we'll break the URI into parts and evaluate them using JSF's built-in EL capabilities. The following is example code for basically implementing the 5 MVC phases with the help of JSF. While there's more to be added, this provides the basics required in pseudo code.

// get our JSF-provided FacesContext
FacesContext faces = FacesContext.getInstance();
Application app = faces.getApplication();

// JSF provides Portlet/Servlet wrapper
ExternalContext ext = faces.getExternalContext();

// EL support from JSF's API
ExpressionFactory elFactory = app.getExpressionFactory();
ELContext el = faces.getELContext(); // local to thread

// to store messages
Map<String, String> msgs = new HashMap<String,String>();
ext.getRequestAttributeMap().put("messages", msgs);

// our view result to forward to when we're done
String result = null;

// 1: decode phase
String action = faces.getViewRoot().getId(); // w/ massaging
Map<String,String> params = ext.getRequestParameterMap();

// 2: validate phase
boolean valid = true;
Map<String,ValueExpression> paramEL = new HashMap();

// enable our ValidateResolver
el.putContext(ValidateResolver.class, Boolean.TRUE);

ValueExpression ve = null;
for (Map.Entry pair : params) {
   try {
     ve = elFact.createValueExpression(el,
                                       "#{"+pair.getKey()+"}",
                                       Object.class);
     paramEL.put(pair.getKey(), ve);

     // ValidateResolver could throw an error here
     ve.setValue(el, pair.getValue());
   } catch (ValidatorException ve) {
     valid = false;
     msgs.put(pair.getKey(), ve.getMessage());
   }
}

// disable our ValidateResolver
el.putContext(ValidateResolver.class, Boolean.FALSE);

// if we validated successfully
if (valid) {

   // 3: update phase
   for (Map.Entry pair : params) {
        ve = paramEL.get(pair.getKey());

        // set it for real
        ve.setValue(el, pair.getValue());
   }

   // 4: invoke phase
   String elAction = "#{"+action+"}";
   MethodExpression me = elFactory.createMethodExpression(el,
                             elAction, Object.class, null);

   Object invResult = me.invoke(el, null);
   result = (invResult != null) ? inResult.toString : null;

   if (result != null) {
      // delegate routing of result
      NavigationHandler nav = app.getNavigationHandler();
      nav.handleNavigation(faces, action, result);
   }
}

// 5: encode
faces.renderResponse();

While the above is only pseudo code, it does show that JSF could be used without needing to use stateful UIComponents with a custom, lightweight MVC framework. Because your framework would have a FacesContext always available, it would be much easier for you to include UIComponents down the road if you so choose.

Conclusion

I guess the point I'm making is that these new frameworks should take advantage of the JSF API, even though you're not using all of it. Facilitating other framework developers with the JSF API is something that should be pursued more vigorously by the JSF EG. With each phase of MVC outlined within JSF and the delegation of concerns around ViewHandlers, NavigationHandlers, ActionListeners, Converters, Validators, etc, the whole stack is very customizable. Ideally, developers could co-habitate MVC solutions on top of the JSF-API such that you can have the best of both worlds with action and component frameworks.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • It's interesting what you said here. Your idea of using JSF API to impement new frameworks make sense. I'm trying to do that :) But there is something you missed in your conclusion. Developing other frameworks that based on particular API even that good as JSF is not always good perspective. Any API eventually become outdated and must provide backward compatibility. Frameworks that oriented on particular API will become too dependend on it and that will keep them down. There is other path that at least partially resolve the problem of redundancy existing frameworks. In fact you already started think in this drection :) I mean you have already started formalization of MVC frameworks. The path: formalization -> model -> implementation Please don't think that I suggest something like UML. UML thing can't play in this situation. I have already started some experiments in area of generation functionaity. For example I'm trying to generate all functionality jsf components based on related model of them. I know that jsf implementation can generate tld and taghandlers. I'm trying to do more than that. It's not too hard for me to implement generation from model such things as database, model beans, config files, business objects, data entry forms, reports or whole business application. Even generation simple JSF components is possible at least I'm very close to that. Challenge is modeling and generation frameworks. JSF is good candidate to try formalization on it because so many patterns implemented here. Best regards, Vladimir

    Posted by: vladperl on March 18, 2006 at 07:48 PM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds