AJAX in a Portlet

Recommended solutions for using AJAX in a portlet

Most of the solutions described on this page require Tomcat to be configured with emptySessionPath set to true.  For more information on this configuration setting, please refer to the uPortal Manual.  The appropriate section for uPortal 3.1 is found here.

AJAX Portlet Support Problem Overview

An approach to perform AJAX callbacks to a portlet completely within the JSR-168 specification. An example portlet and generic support library for this approach are also linked to below.

AJAX in Portlet Hurdles

  • URL structure, including parameter name format, is dictated by the portal. This results in restrictions in how the JavaScript performs the callbacks.
  • Portlets render just a fragment of content that is surrounded by portal content, this means Portlet.render is not an option for responding to AJAX callbacks as the entire portal-page renders.

AJAX in Portlet Solutions

  • There are no limitations to the parameter names in a form POSTed to a Portlet ActionUrl. This allows AJAX code to perform requests via a POST to an ActionUrl rendered by the portlet.
  • During a Portlet.processAction the portlet can send a HTTP 302 redirect to a Servlet packaged in the same WAR. This allows the Servlet to handle rendering the response to the request.
    • To pass data from the Portlet processAction to the Servlet object data is placed in the PortletSession at the APPLICATION_SCOPE using a random key which is then passed on the Servlet URL.

AJAX in Portlet Support

An add-on library has been developed to provide the common base services around doing AJAX in a Portlet following the above formula. The support library can be used by depending on the following Maven artifact:

<dependency>
    <groupId>org.jasig</groupId>
    <artifactId>AjaxPortletSupport</artifactId>
    <version>1.0.7</version>
</dependency>

The code for the support library is available in SVN at: https://www.ja-sig.org/svn/sandbox/AjaxPortletSupport/tags/rel-1.0.0
An example portlet using this library is available in SVN at: https://www.ja-sig.org/svn/sandbox/AjaxNotepadPortlet/trunk/

AjaxPortletSupport Usage

There are two approaches for using the support library.

Option 1 - Inheritance based Spring Controllers

Extend org.jasig.web.portlet.mvc.AbstractAjaxController and implement the Map<Object, Object> handleAjaxRequestInternal(ActionRequest, ActionResponse) method.

protected Map<Object, Object> handleAjaxRequestInternal(ActionRequest request, ActionResponse response) throws Exception {
    final Map<Object, Object> model = new HashMap<Object, Object>();
    final Data d = this.applicationApi.getData(request);
    model.put("data", d);
    return model;
}

Configure your implementation of AbstractAjaxController as you would any other controller.

Configure org.jasig.web.servlet.mvc.AjaxResponseController as a Servlet controller. The default path that AbstractAjaxController expects for the controller is ajaxResponse but that can be configured via the ajaxServletName property. The AjaxResponseController renders with the view named jsonView by default, the view name can be configured via the viewName property.

Your application code then should POST via a portlet ActionURL to your AbstractAjaxController implementation. Once the data is returned from handleAjaxRequestInternal it will be stored in the user's session with a random key and then a redirect is sent to the rendering servlet with the key. The rendering servlet gets the data out of the session and returns it as part of the ModelAndView to render.

Option 2 - Using SessionKeyGenerator and ModelPasser Directly

If your application is using a different MVC framework or the Spring annotation based MVC support you'll need to use the ajax support service API directly.

The org.jasig.web.service.AjaxPortletSupport interface defines methods for passing a data model to the rendering serlvet and for getting the data model in the rendering servlet. The default implementation org.jasig.web.service.AjaxPortletSupportService should be sufficient for most uses.

In the code that handles the portlet ActionRequest the following logic flow is used:

this.ajaxPortletSupportService.redirectAjaxResponse(this.ajaxServletName, request, response, new ModelGenerator() {
    public Map<Object, Object> generate(ActionRequest request, ActionResponse response) throws Exception {
        final Map<Object, Object> model = new HashMap<Object, Object>();
        final Data d = applicationApi.getData(request);
        model.put("data", d);
        return model;
    }
});

In the servlet that renders the response to the AJAX request the following logic flow is used:

final Map<Object, Object> model = this.ajaxPortletSupportService.getAjaxModel(request, response);
return new ModelAndView(this.viewName, model);

AjaxPortletSupportService.getAjaxModel will set a return code of 404 if no model is found in the session for the key, null is returned by the call in this case. If an error generating the model was signaled by the AjaxPortletSupportService.redirectAjaxResponse a 500 return code is set and the model which should contain the causing exception is returned by the call in this case.

AJAX Portlet Support Request Diagram

In the code that handles the processAction request the following logic is needed:

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.