Thursday, January 31, 2008

Stripes 1.5 Feature: General Improvements

My last two Stripes articles covered Clean URLs and @StrictBinding. Today I am going a bit more general and discussing several of the smaller improvements.

Disclaimer - We know that other web frameworks have had some of these features in some form or fashion so please don't comment with "ZZZ Framework has been doing that for years.". We know. We get it.

@DontValidate

This annotation has been in Stripes for a while. We would typically use this for cancel events or just any event where you don't want validation to occur. The problem however was that type converting still happens and if it fails errors are generated and your event won't complete. This has been changed in 1.5 so now @DontValidate will also ignore type conversion.

@DontBind


Yesterday I talked about @StrictBinding and how you can control data binding using the annotation and validation. Since @StrictBinding is a class level annotation it makes it nearly impossible to do this on a per event basis. @DontValidate helps but binding still occurs. @DontBind implies @DontValidate and does not attempt any binding of data.

@HttpCache

Back in November of last year I blogged about how easy it is to create an interceptor for Stripes and we created the @NoCache interceptor. This interceptor has been added to Stripes core in 1.5 but with a twist. It is now called @HttpCache and you can control the no-cache and expires parameters via annotation attributes. Lets look at an example.

@HttpCache(expires=600)
public Resolution ajaxUpdate() {

}

The above example will allow caching but expires the document in 10 minutes.

@HttpCache(allow=false)
public Resolution ajaxUpdate() {

}

The above example disables caching and immediately expires the document. This comes in really handy when returning Resolutions to AJAX requests (especially in IE). @HttpCache can be applied at the class or method level. Method level annotations will always override class level annotations.

@Before/@After

These annotations have been available in Stripes for a while but now can be set to run on certain events. Lets look at an example.

@After(on = {"save","edit"}, stages = LifecycleStage.BindingAndValidation)
public Resolution runAfterBinding() {

}

The above method will only execute on the save and edit events. Multiple LifecycleStages can also be specified. @Before works the same way.

There are also quite a few more subtle but significant changes. Here they are in no particular order of importance.

  • When you create a link that doesn't pass validation and there is no _sourcePage to go to, you get a nice validation error report that tells you what you did wrong instead of getting a StripesRuntimeException and having to jump through hoops to figure it out

  • Incoming requests are no longer wrapped multiple times when you map StripesFilter on FORWARD. Solves problems that existed with wrapping multipart requests more than once (big explosion) and other silly issues that would occasionally arise from wrapping multiple times.

  • Enhanced checking of stuff (multiple @Validate, multiple @DefaultHandler) etc. Stripes now does a much better job at notifying you about trivial issues that can be a pain to track down. For example if you annotated two methods with @DefaultHandler Stripes would just pick one and determining why you weren't getting the expected results was time consuming. Now Stripes will throw an exception and tell you exactly what the problem is.

  • Reduced Session use. Stripes used to store encryption keys in the HttpSession. Now that it doesn't stripes doesn't force session creation of any kind.

  • Lots of changes with classpath scanning so that Stripes plays nicer with container/custom class loaders.

  • Most things in Stripes can be easily overridden to support a wide array of scenarios we can come up with as web developers. ActionResolver, ActionBeanContext, TypeConverters, just to name a few. While Stripes prides itself on zero ActionBean configuration you still need to specify init params for the Stripes Filter in the web.xml and that includes any core classes you want replaced with your own custom versions. Stripes now offers an init param, Extension.Packages, that accepts a comma separated list of packages where Stripes will auto discover and load any custom classes that would override Stripes default classes. This can significantly reduce the amount of configuration required in the web.xml


There are a few more enhancements that need to be discusses however they require their own articles respectively. I hope everyone is enjoying these articles. More to come in the days ahead, I assure you.

Wednesday, January 30, 2008

Stripes 1.5 Feature: Control Binding with @StrictBinding

If you missed yesterday's article on Clean URLs you can find it here. Today I want to talk about how we can control what values get bound in an Action Bean when we submit a form. And once again;

Disclaimer - We know that other web frameworks have had some of these features in some form or fashion so please don't comment with "ZZZ Framework has been doing that for years.". We know. We get it.

The Stripes team has added a very useful annotation as well as some supporting changes to an existing annotation to provide a first line of defense against hackers. This annotation is @StrictBinding. This is a class level annotation and uses the @Validate annotation as support. First we can look at a basic example:

@StrictBinding
public class RegisterActionBean extends BaseActionBean {

private User user;
}


In this example any values submitted by a form to this action bean won't be bound at all. Hmm, not very useful. So lets tweak it a bit.

@StrictBinding(allow="*")
public class RegisterActionBean extends BaseActionBean {

private User user;
}


This will allow binding to any top level properties in user. However, nested properties are ignored. Not quite what we need yet. One more modification.

@StrictBinding(allow="**")
public class RegisterActionBean extends BaseActionBean {

private User user;
}


Alright, the double * in the allow attribute says bind everything, no matter how nested. Another way to achieve the same thing is to use defaultPolicy=Policy.ALLOW instead of "allow". If we need finer grained control we can also use the "deny" attribute.

@StrictBinding(allow="**", deny="user.role.id")
public class RegisterActionBean extends BaseActionBean {

private User user;
}


This allows everything to bind except for user.role.id because we don't want a new user to be able to specify their own security level by adding parameters sent to the server. That would be bad. And with that I think you can see the benefit of @StrictBinding. It is a good first line defense mechanism. But we're not done yet.

@StrictBinding all by itself can handle anything you need however the preferred way to control binding is with @StrictBinding + @Validate. Lets look at another example.

@StrictBinding
public class RegisterActionBean extends BaseActionBean {

@ValidateNestedProperties({
@Validate(field="username", required=true),
@Validate(field="password", required=true),
@Validate(field="firstName", required=true),
@Validate(field="lastName", required=true)
})
private User user;
}


First we turn off all binding using the simplest form of @StrictBinding. Then, we control the binding with validation. Any property being validated is bound. Everything else is ignored.

As always data should be sanitized but with the addition of @StrictBinding, Stripes provides a very elegant first line of defense against intruders.

Tuesday, January 29, 2008

Stripes 1.5 Feature: Clean URLs

So I promised a list of some new features coming in Stripes 1.5. Since several of them require some explanation to really get the point across I decided to do a daily article about each of the major feature improvements and then one final article on the smaller things. I finally found a bit of time so here is the first one. Stripes 1.5 is coming along really well. The developers have been committing code like crazy the past month. We should be seeing a beta release really soon.

Disclaimer - We know that other web frameworks have had some of these features in some form or fashion so please don't comment with "ZZZ Framework has been doing that for years.". We know. We get it.

Clean URLs have been possible in Stripes for a while through an add on. However, with Stripes 1.5 they will be an optional feature in the core API. As you may or may not know currently you can define a URL Binding for a Stripes action one of 2 ways. You can let Stripes handle it by inspecting the package and class name and binding it for you or you can explicitly set it using the @UrlBinding annotation. With clean URLs @UrlBinding is required. The format is something like:

@UrlBinding("/action/blog/{$event}/{blog.id}")
public class BlogActionBean...

The resulting URL to edit a blog entry would be:

http://.../app/action/blog/edit/1234

If the event is null it is ignored as well as any given parameter. So a URL like:

http://.../app/action/blog

would result in calling the Default Handler for the BlogActionBean. Support for default parameter values are also available.

@UrlBinding("/action/blog/{$event}/{blog.id=1234")

So accessing the url

http://.../app/action/blog

blog.id will have a value of 1234 however if you pass in a blog.id value it will override the default. Default values for {$event} can also be given. This overrides the @DefaultHandler method if one exists. Otherwise, the @DefaultHandler method is executed.

If you still prefer extensions on your URLs, support for that is also available. The change to the URL binding is trivial:

@UrlBinding("/blog/{$event}/{blog.id}.action")

Stripes JSP tags <s:url />, <s:link />, and <s:form /> all support Clean URLs. For example:

<s:link beanclass="com.app.foo.BlogActionBean" event="edit">
<s:param name="blog.id">1234</s:param>
Edit
</s:link>


Will result in:

<a href="/app/action/blog/edit/1234">Edit</a>

And that is pretty much it for Clean URLs in Stripes 1.5. Very simple, elegant, and as good as the next guys. Possibly better? Let me know.