2.7. Page Actions

Page Action is a feature to directly invoke a Page method from the browser. The Page Action method returns an ActionResult object that is rendered directly to the browser. In other words the Page template will not be rendered.

To invoke a Page Action, specify the parameter "pageAction" and the name of the page method, for example: "onRenderImage".

Let's take a quick look at how a Page Action can be leveraged to retrieve an image. In this example we'll create an HTML <img> element which src attribute specifies the Page Action that will return the image data.

First we create our template:

<img src="$context/mycorp/image.htm?pageAction=onRenderImage"/>

Next we create our ImagePage with a Page Action method called onRenderImage that returns an ActionResult instance:

public class ImagePage extends Page {

    public ActionResult onRenderImage() {
        byte[] imageData = getImageAsBytes();
        String contentType = ClickUtils.getMimeType("png");
        return new ActionResult(imageData, contentType);
    }
} 

A Page Action is a normal Page method with the following signature: a public no-arg method returning an ActionResult instance:

// The Page Action method is public, doesn't accept any arguments and returns an ActionResult
public ActionResult onRenderImage() {
    byte[] imageData = getImageAsBytes();
    String contentType = ClickUtils.getMimeType("png");
    return new ActionResult(imageData, contentType);
} 

The ActionResult contains the data that is rendered to the client browser. In the example above, the result will the Image byte array with a Content-Type of: "images/png".

2.7.1. Page Action Execution

Page Actions are page methods that handle the processing of a user request and render a result to the browser. The execution sequence for a Page Action being processed and rendered is illustrated in the figure below.

Page Action Request Sequence Diagram

Figure 2.5. Page Action Request Sequence Diagram


Stepping through this Page Action request sequence, a new Page instance is created and the attributes for the Page are set (format, headers). Next, request parameter values are bound to matching Page fields.

Then the onSecurityCheck() handler is executed. This method can be used to ensure the user is authorized to access the Page Action, and if necessary abort any further processing. If onSecurityCheck() return false, no response is sent back to the client. Note, if you want to send a specific response to the client you have to do that from the onSecurityCheck() event, since other Page events are not executed. Please see this example for some strategies on implementing onSecurityCheck to handle ajax requests.

Next the target page method is invoked which returns an ActionResult that is rendered to the client.

If the page method returns null no response is rendered to the browser.

2.7.2. ActionResult

An ActionResult represents the content returned by a Page Action which is then rendered to the client browser. ActionResults normally contains HTML or image data that is rendered to the browser. When a Page Action is invoked the Page template rendering is bypassed and only the ActionResult content is rendered to the browser. This allows a Page Action to return a "partial" response, as opposed to a "full" response, because the Page template (which can be viewed as a "full" response) is bypassed when invoking a Page Action.

2.7.3. Page Action Example

Let's step through a Page Action example. First we create an ImagePage class with the method "getImageData" which is the Page Action we want to invoke:

public ImagePage extends Page {

    public ActionResult getImageData() {
        byte[] imageData = loadImageData();
        String contentType = ClickUtils.getContentType("png");
        return new ActionResult(imageData, contentType);
    }
} 

Next we have the page template image.htm:

<html>
  <body>

    <img src="/mycorp/image.htm?pageAction=getImageData"/>

  </body>
</html> 

The browser renders the <img> element and requests the image src url. Click invokes the page method getImageData and renders the result to the browser.

Looking at the output log we see the following trace:

[Click] [info ] handleRequest:  /image.htm - 84 ms
[Click] [debug] GET http://localhost:8080/mycorp/image.htm
[Click] [trace]    is Ajax request: false
[Click] [trace]    request param: pageAction=getImageData
[Click] [trace]    invoked: ImagePage.<<init>>
[Click] [trace]    invoked: ImagePage.onSecurityCheck() : true
[Click] [trace]    invoked: ImagePage.getImageData() : ActionResult
[Click] [info ]    renderActionResult (image/png) - 0 ms
[Click] [trace]    invoked: ImagePage.onDestroy()
[Click] [info ] handleRequest:  /image.htm - 98 ms

2.7.4. Accessing Request Parameters

Request parameters can be accessed through the Context as shown below:

public ImagePage extends Page {

    public ActionResult getImageData() {
        // Retrieve a request parameter through the Context
        Context context = getContext();
        String imageName = context.getRequestParameter("imageName");

        byte[] imageData = loadImageData(imageName);
        String contentType = ClickUtils.getContentType("png");
        return new ActionResult(imageData, contentType);
    }
} 

2.7.5. Set response headers and status code

When handling a Page Action you might need to set the HTTP response headers or status code. You do this through the Servlet API's, HttpServetlResponse which can be accessed through the Context.

For example:

package examples.page;

import java.util.Date;
import org.apache.click.Page;

public ImagePage extends Page {

    public ActionResult getImageData() {
        // Headers and Status code are set on the HttpServletResponse
        HttpServletResponse response = getContext().getResponse();

        // The headers can be set as follows:
        response.setHeader("Content-Disposition", "attachment; filename=\"report.xls\"");

        ...

        // The response status can be set as follows:
        response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);

        ...
    }
}