Rethink Web Apps in the light of Generics

The following is some musings on Templates and generics. I am not advocating programming this way, just trying to think through these issues in a framework I’ve used before.

The Struts framework dominated web application development in the Java world until the introduction of Java Server Faces. Since Java 1.4 and earlier provide great introspection capabilities and no generics, Struts did heavy runtime introspection to initialize the application and interpret URLS into the paths of the Java classes that should process them. The heart of form processing in Struts is the Action and ActionForm classes. Bascially, struts uses property names to map HTML parameters to bean ‘set’ methods. These can be nested. For instance

orderForm.billingAddress.phoneNumber.areaCode=415

would map to

OrderForm form = session.getBean(“order”);

form.getAddress().getBillingAddress().getPhoneNumber().setAreaCode(“415”)

albeit executed via reflection. Once the form object is populated it is passed to an Action Object. The Action object is an instance of the Flyweight Design Pattern. A Single Action instance can process all of the forms submitted at a time. Note that an Action object is not a singleton: Two instances of the same subclass of Action can be instantiated and have state assigned from the configuration file. They are only “Stateless” with regard to the HttpRequest, HttpResponse, and HttpSessions. Here is the API:

public class ExampleAction extends Action
{

public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception{}

}

The ActionMapping allows you to get specifics about how the action was configured. Mostly it is used to figure out where to go next. The Action form is either down-cast to the correct type (throwing an exception if it is the wrong type) or ignored if there is no submitted data. The mapping class contains a list of forwards. These forwards are kept in a map. The action is going to return a forward configured like this:

return mapping.findForward("success");

We have here several instances of Runtime processing about decisions that could be made at compile time. The code that makes these decisions could be optimized by the compiler. Let’s start with the mapping. A map lookup based on a string is fairly expensive: Either has the string and do a hash-table lookup, or do a series of string compares. Really, what we want is code like:

template <typename Mapping, typename Form>

ActionForward execute(Form form, Mapping map, HttpRequest req, HttResponse resp) {

return map.forwardSuccess;

}

The java Bean API is based on a Java d design decision that everything class type variable a reference. To ensure that you don’t get a Null pointer, you have to fetch something through a ‘get’ method that often acts as a Lazy accessor. This is not necessary for most uses. C++ has the alternative of objects owning the objects they create. Thus the map object, even if created on the stack, can own the forward object. To transform the above in C++, it would be more like:

ActionForward& execute(Form& form, Mapping& map, HttpRequest& req, HttResponse& resp) {

return map.forwardSuccess;

}

The ‘&’ ensures that there is no copying of the objects through the function call. Because the map and returned action forward object both live outside the scope of this function, you can return a reference to the forward. This is true even if the map was originally created on the stack. We’ll come back to that in a little bit.

One task that actions often have to perform is validate a form an return to the previous screen if the form is invalid. In our above code, the logic would be:

ActionForward& execute(Form& form, Mapping& map, HttpRequest& req, HttResponse& resp) {

if (form.isValid() ){

return map.forwardSuccess;

} else {

return map.forwardPrevious;

}

Note that with templates, you could go crazy and have the forward and previous actions, as well as the isValid function name all passed in as template parameters. This would be the ulitmate in flexibility. The question here is the middle ground of settling on an acceptable implied interface.

Let’s take the case of the bean setters being called.

orderForm.billingAddress.phoneNumber.areaCode=415

Code like this is usually generated from a struts tag embedded inside a JSP. Here, code generation (JSP compilation) is generating late bound code. Even without the Generics capabilities of Java 1.5 and later, this can be bypassed, and in fact “pure” jsp processing does that by doinbg the bean API translation in line. However, struts does not have access to the JSP grammer and could not define rules for translation at that point. It only had the weaker rules of the JSP tag API, and thus had to be content with run time binding.

When the servlet API calls the struts servlet onPost method, the struts servel iterates through all of the parameters performs a binding on each one. The cope of the Form is defined by the action mapping that thje JSP refers to in the <FORM> tag. The code in the JSP is something like this:

<form action=”myurl.com/struts/thisform/sumbit.do”>

<input type=”text” name=”billingAddress.phoneNumber.areaCode”>

The URL will be translated to the mapping in the struts config file (minus the .do). The form object is a Bean, usually Session scoped, defined in the same file. Once that is resolved, the rest of the lookup is done using a util function for properties. To convert this to Template style, the first lookup would have to remain the same. URLS can be either absolute or relative. However, we can use functors for the second part: Validating and setting property values. We know what values will be used on a given page. A functor can handle the validation and the setting.
Map <string, string> properties;

Map <string, string>:: data_type data;

Map <string, string>:: iterator_type iterator;

for(iterator = properties.begin(); iterator != properties.end() iterator++){

data = *iterator;

propName,propValue in request

try{

mapping.propertyMap.get(data.first).set(form,data.second));

}catch(ActionException& ae){

actionErrors.add(ae);

}

}

Some people question the efficiency of using Exceptions for handling code of this type. I’ve addressed that in an earlier blog post. Basically, entering a try block generated by g++ is free. The only cost is when the exception is thrown: A new object has to be created and the stack unwound to the point where that exception is handled. The cheapest way to write this code would be to return an error code from action errors, but that propertyMap.get(“”).set(form,””). But then the setter has no way to customize the error message. We could pass back a string or null to signify error or success, but now we are already allocating objects, and adding in an additional test done for every success condition.

If we were to peek beneath the covers of struts into how the code was written for the ActionMapping we would see something like:

getAction().execute(request, response, form,this);

This is where the template parameter comes into play:

template<typename Form, typename Action> ActionMapping : public Mapping{

Mapping(Action& action){

}

process(HttpRequest req HttpResponse resp){

action.execute(request, response, getForm(req),this);

}

}

We still need to descend from a common Mapping baseclass so that the Action and Mapping classes don’t have a circular dependency. But now we have type safety in the call into the Action. Also, the construction of the mapping depends on a specific class. Initializing this code now has to be done in C++. Both the Mapping and the Action objects should be scoped global to the application. The Form can either be request or session scoped. Thus the construction of this complex set of relationships will require a lot of thought.

This article could go on and on. I’m going to add one more related concept and then declare victory and post it.

The difference between a Form object and the domain model is that the form object shuld be able to work with half formed, invalid data. Quite often, the form will contain builders for objects in the domain model. A Trivial example is a social security number. This is of the format 000-11-2222. Often, the UI will put each of these fields into a separate text box. The builder will then accept each field, validate their length and that it only has didgits, and produce a SocialSecurityNumber.

One way that this could be made generic is to provide a Template class that represents a validator for a regular expression. The SocialSecurity Number would be one instance, but each of the sub fields would be instances as well. Someething like this:

typedef ValidatedString<“\d\d\d-\d\d-\d\d\d\d> SocialSecurityNumber;

This is not valid C++, as the string cannot be passed to a type. It might be OK in Java where Regular Expressions are processed at run time.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.