
A major upgrade of the Loom web framework has been released. We made it a major version change since it includes some breaking changes in places where backwards-compatible was just not worth it.
Tag documentation has been improved a lot, but there are other features also worth seeing:
Works with AppEngine
We have been developing our own share of projects with Loom, and some are running in AppEngine. To make this possible we have forked a subproject with AppEngine image validation, datastore type converters (Key, GeoPt, etc), and transparent support for binding SimpleDS paged queries into paged tags.
Cache page fragments
We have added session and application-level caching of page fragments, such as:
<l:cache id="application-menu" scope="application">
<!-- application menu goes here -->
</cache>
Fragments can be cached separated by locale or not. This implementation is really simple, and things like cache timeout are not included yet.
Event parameters
Events now accept parameters:
public class BlogEntriesAction extends AbstractAction {
// parameter name is required
@Path("baz")
public Resolution baz(@QueryParam("id") int id) { ... }
// parameter name is not required when embedded in the URL
@Path("bar/{foo}")
public Resolution bar(String foo) { ... }
// You can mix embedded and non-embedded parameters, but
// embedded are expected to be resolved left-to-right
@Path("bazbar/{foo}")
public Resolution bazbar(String foo, @QueryParam("bar") int bar) { ... }
}
New JSON support
We finally deprecated our quick-and-dirty JSON implementation to adopt jackson. This makes some nice features possible:
// return a JSON response
public Resolution doFoo() {
return json(myObject);
}
// receive JSON objects as parameters
public Resolution bar(@JSON @QueryParam("baz") baz) { /* ... */ }
// render as JSON inside a page
public Resolution doFoo() {
return forward("mypage.jsp").setAttribute("bar", bar);
}
<script>
alert(${l:json(bar)});
</script>
Uploaded files
A breaking change introduced in 2.0 is that file uploads are no longer being automatically bound to java attributes. From now on you must handle these parameters yourself, and this affects the way file validations are being performed:
@FileValidation(
parameterName="uploadedDocument",
formats={ "txt", "rtf" },
maxFileSize=1024000)
public Resolution saveDocument() {
fileManager.merge(getRequest().getFileParameter("uploadedDocument"));
}
@ImageValidation(
parameterName="uploadedImage",
formats={ "jpg", "gif" },
maxWidth=100,
maxHeight=100,
maxFileSize=1024000)
public Resolution saveDocument() {
fileManager.merge(getRequest().getFileParameter("uploadedDocument"));
}
New paged features
Now you can use more than one paged container (table or list) in the same HTML page, or inject a plain Collection to be conveniently displayed as a single page.
Also: JSON paged lists! PagedListData instances can now be serialized JSON and handled by javascript to render the same HTML contents generated by the server-side tag.
More details about the current paged tags status can be found here.
New information methods
A new set of static methods MessageUtils.info(), warn() and error() have been added, which can be invoked anywhere in your code.
public class MyServiceImpl implements MyService {
public void myService() {
entityManager.put();
MessageUtils.info("save.success");
}
}
Messages are serialized in case of a redirect, and will be displayed on the next web request.
SSLPolicy
A new annotation has been added to indicate the level of encryption on the annotated events:
@SSLPolicy(REQUIRES_INSECURE)
public class FooAction extends AbstractAction {
public Resolution event1 {
// this event requires http:
}
@SSLPolicy(REQUIRES_SECURE)
public Resolution event2 {
// this event requires https:
}
}
Recaptcha support
In this release we are migrating from JCaptcha into ReCaptcha, since it seems to be the only implementation designed to face Human Computation attacks. It is also much easier than JCaptcha to configure and use, which is a plus.
@Recaptcha
public Resolution save() { ...}
<l:form action="Foo" event="save">
<a:recaptcha publicKey="[publicKey]"/>
</l:form>
The bad news is that the scaffolding tool is not yet up-to-date so we had to drop it from this release. It will be added again when time permits :)
The full changelog is here, the list of breaking changes is here, and comments, as usual, are welcome :)