Download

Get Loom

Method annotations

JAX-RS annotations

These annotations can be used to modify an Action/Event mapping (for example to receive parameters embedded in the URL) and specify the supported HTTP methods.

// by default this action would have been mapped as /blog-entries/
@Path("/entries")
public class BlogEntriesAction extends AbstractAction {

  // /entries/foo (GET/POST) 
  public Resolution foo() { ... }

  // /entries/foo-bar (DELETE)
  @DELETE @Path("foo-bar")
  public Resolution bar() { ... }

  // receive one "id" parameter 
  @Path("baz/{id}")
  public Resolution baz() { ... }

  // receive three parameters, the last one is optional
  @Path("create/{entry.year}-{entry.month}-{entry.day?}")
  public Resolution create() { ... }

}

The following JAX-RS annotations are supported: @Path, @GET, @POST, @DELETE and @PUT

Event

This annotation modifies the annotated event, setting methods that should be invoked on each workflow phase:

@Event(default=true, beforeValidate="foo", beforeExecute = "maybe")
public Resolution edit() {
	return forward("somepage.jsp");
}

public Resolution maybe() {
	// return not null if you want to skip the event execution
	return something? null : forward("otherpage.jsp");
}

public void foo() {
	// Interceptors that will never interrupt the execution workflow 
	// may return void instead. They will get executed, but they cannot 
	// change the execution flow
}

Listener methods may return void if they do not pretend to stop the workflow, or a not-null Resolution to skip the rest of the workflow.

File upload annotations

Events can specify requirements for file uploads:

@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("uploadedImage"));
} 

Note that dfor this to work you must have configured FileValidationAnnotationProcessor / FileValidationInterceptor or ImageValidationAnnotationProcessor / ImageValidationInterceptor in your spring context, respectively.

Security annotations

JSR-250 and Spring Security (formerly known as Acegi) provide the following annotations to restrict the user roles that may invoke a certain method:

  • RolesAllowed (JSR-250) and Secured (spring): Specify the list of roles that may invoke a method.
  • DenyAll (JSR-250): No user may invoke this method.
  • PermitAll (JSR-250): Any user may invoke this method.
@RolesAllowed({ "admin", "helpdesk"})
public class MailAdminAction extends AbstractAction {

	@RolesAllowed({"admin"})
	public Resolution create() {
	// ...event method code...
	}
}

Loom supports using these annotation on Action classes and event methods. If both are specified, the method annotation prevails. Requests to an event without the required roles will trigger a 401 (forbidden) response.

Menu items that link to an unauthorized action/event will not be rendered by default for security reasons. Any other link that points to an unauthorized event will have a "unauthorized" css class automatically added, which could be used to customize behavior using CSS or javascript.

Cache

The CacheControl class can be used manually, but it's cumbersome since you would have to manually check each request and decide what to return. To handle this, Loom includes a @Cache annotation that can be attached to the method that calculates the cache metadata, and will automatically return a 304 if the resource has not been modified (skipping the event execution):

public class FileAction extends AbstractAction {

	@Injected
	private FileManager fileManager;
	
	@RequiredValidation(on="get*")
	private Integer id;
	
	private PersistentFile file;
	
	@Cache(on="getFile")
	public CacheControl getCacheControl() {
		file = fileManager.find(id);
		CacheControl c = new CacheControl();
		c.setLastModified(file.getLastModified());
		return c;
	}
	
	public Resolution getFile() {
		return send(file);
	}
	
}

In this example, getFile() will only be invoked if the request "If-Modified-Since" header is not a match for the returned CacheControl.lastModified attribute. Other caching options may be used like etag or cache seconds.

SSLPolicy

SSLPolicy is an annotation that can be attached to Action classes or Event methods, and indicates the https/http requirements to invoke all the action events or this concrete event, respectively. There are three possible values:

  • REQUIRES_SECURE: A secure (https) scheme is required.
  • REQUIRES_INSECURE: An insecure (http) scheme is required.
  • DO_NOT_MODIFY: Any incoming scheme (http/https) is allowed.

The default SSLPolicy is DO_NOT_MODIFY, but it can be overriden using Config.defaultSSLConfig in the spring config file.

@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:
	}
	
}

If a GET request does not satisfy the SSLPolicy it will get redirected appropriately. Other requests (POST, DELETE, etc) that do not conform to the policy will be rejected.

Links and forms will have the correct scheme (https, http) automatically added to the target URL if it differs from the current one.

If you are using spring-security, the configured pairs of http-https port mappings will by used. By default, these are: http 80 - https 443, http 8080 - http 8443.