Tuesday, April 19, 2016

JSR 286 Lifecycle Explained

Though age old, thought of writing this post just to have a placeholder to detail the basic JSR 286 Portlet flow.

Following flow chart explains the basic flow of JSR 286 based portlet:


JSR 286 based portlet's flow

By overriding the major methods of GenericPortlet class and adding loggers on each method entry, we can easily view the flow of the portlets lifecycle.
  • After deploying the portlet, when it is being invoked for the first time (by visiting a page on which it is added) init method is called.
[2/18/16 17:10:55:925 IST] 000001c5 SystemOut     O JSR286LCCheck init method called
[2/18/16 17:10:55:926 IST] 000001c5 SystemOut     O JSR286LCCheck render method called, mode to be displayed is : view
[2/18/16 17:10:55:926 IST] 000001c5 SystemOut     O JSR286LCCheck doDispatch method called
[2/18/16 17:10:55:926 IST] 000001c5 SystemOut     O JSR286LCCheck doView method called

  • For all other subsequent calls, init is not invoked. On page refresh:
[2/18/16 17:13:23:309 IST] 00000145 SystemOut     O JSR286LCCheck render method called, mode to be displayed is : view
[2/18/16 17:13:23:310 IST] 00000145 SystemOut     O JSR286LCCheck doDispatch method called
[2/18/16 17:13:23:310 IST] 00000145 SystemOut     O JSR286LCCheck doView method called

  • On Form submit processAction is invoked and flowing is the flow: (Changed the portlet mode here to Edit mode). doDispatch redirects to the requested mode method:
[2/18/16 17:12:03:436 IST] 00000044 SystemOut     O JSR286LCCheck processAction method called
[2/18/16 17:12:03:741 IST] 00000044 SystemOut     O JSR286LCCheck render method called, mode to be displayed is : edit
[2/18/16 17:12:03:741 IST] 00000044 SystemOut     O JSR286LCCheck doDispatch method called
[2/18/16 17:12:03:741 IST] 00000044 SystemOut     O JSR286LCCheck doEdit method called


Once the mode is changed, it remains in the same mode till session is over or the mode is changed explicitly.
  • When serveResource is called, then only serveResource is called. It acts as an independent method.
[2/18/16 17:12:40:239 IST] 00000145 SystemOut     O JSR286LCCheck serveResource method
  • When the application is stopped, destroy method is called. Destroy will only be called if the portlet has been initialized / invoked. If the portlet has not been initialized, the destroy method will not be called.
[2/18/16 17:14:13:292 IST] 00000048 ApplicationMg A   WSVR0217I: Stopping application: PA_JSR286LCCheck
[2/18/16 17:14:13:301 IST] 00000048 ServletWrappe I com.ibm.ws.webcontainer.servlet.ServletWrapper doDestroy SRVE0253I: [PA_JSR286LCCheck] [/wps/PA_JSR286LCCheck] [/_JSR286LCCheck/jsp/html/JSR286LCCheckPortletView.jsp]: Destroy successful.
[2/18/16 17:14:13:302 IST] 00000048 ServletWrappe I com.ibm.ws.webcontainer.servlet.ServletWrapper doDestroy SRVE0253I: [PA_JSR286LCCheck] [/wps/PA_JSR286LCCheck] [/_JSR286LCCheck/jsp/html/JSR286LCCheckPortletEdit.jsp]: Destroy successful.
[2/18/16 17:14:13:302 IST] 00000048 SystemOut     O JSR286LCCheck destroy called
[2/18/16 17:14:13:302 IST] 00000048 ServletWrappe I com.ibm.ws.webcontainer.servlet.ServletWrapper doDestroy SRVE0253I: [PA_JSR286LCCheck] [/wps/PA_JSR286LCCheck] [JSR286LCCheck]: Destroy successful.
[2/18/16 17:14:13:584 IST] 00000048 ApplicationMg A   WSVR0220I: Application stopped: PA_JSR286LCCheck


Tuesday, April 12, 2016

Annotated serveResource in JSR 286 portlet


I wonder why serveResource method was left out while providing annotated methods in JSR 286.
It is a frequent requirement now-a-days to implement multiple AJAX calls while developing JSR 286 based portlets.
There are many different design patterns through which this can be achieved, but still thought of giving a try to annotate serveResource method.

What I did was creating a base portlet class which will be extended by the other portlet classes, but this is not required and can be directly done in the requisite portlet class.

Firstly, created an annotation interface ResourceMapping, this defines the annotation of @ResourceMapping with name as a variable.



package in.blogspot.wpwizard.portlets;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
public @interface ResourceMapping {
 String name();
}

Then in BasePortlet class added a private method to cache the annotated resource methods during the portlet initialization.
Then in the overridden serveResource method checked value of parameter javax.portlet.serveResource which should denote the name of the annotated methods name parameter.



package in.blogspot.wpwizard.portlets;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;



public abstract class BasePortlet extends GenericPortlet {
 private transient Map<String, Method> serveResourceHandlingMethodsMap = new HashMap<String, Method>();


 @Override
 public void init() throws PortletException {
  super.init();

  try {
   cacheAnnotatedResourceMethods(); //cache annotated resource serving methods on init
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 @Override
 public void destroy() {
  super.destroy();
 }

 /**
  * In order to annotate the serveResource use <code>@ResourceMapping</code> 
  * and provide the variable name of parameter <code>javax.portlet.resource</code> in <code>resourceURL</code> 
  * 
  */
 public void serveResource(ResourceRequest request, ResourceResponse response)
   throws PortletException, IOException {
  try {
   String resource = request.getParameter("javax.portlet.serveResource");
   Method resourceMethod = serveResourceHandlingMethodsMap.get(resource);
   if (resourceMethod != null) {
    resourceMethod.invoke(this, request, response);
    return;
   }
  } catch (Exception e) {
   throw new PortletException(e);
  }

 }


 @Override
 protected void doView(RenderRequest request, RenderResponse response)
   throws PortletException, IOException {

 }


 private void cacheAnnotatedResourceMethods() {
  // cache all annotated resource serving methods
  for (Method method : this.getClass().getMethods()) {
   Annotation[] annotations = method.getAnnotations();
   if (annotations != null) {
    for (Annotation annotation : annotations) {
     Class<? extends Annotation> annotationType = annotation.annotationType();
     if (ResourceMapping.class.equals(annotationType)) {
      String name = ((ResourceMapping) annotation).name();
      if (name != null && name.length() > 0)
       serveResourceHandlingMethodsMap.put(name, method);
     } 
    }
   }
  }
 }

}

In the individual portlet class of MyPortlet added the annotated methods for serving resource.



package in.blogspot.wpwizard.portlets;

import java.io.IOException;
import java.io.PrintWriter;

import javax.portlet.PortletException;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;


public class MyPortlet extends BasePortlet {
  
 public void init() throws PortletException{
  super.init();
 }

 public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
  
  response.setContentType(request.getResponseContentType());
  PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher("/jsp/view.jsp");
  rd.include(request,response);
 }

 @ResourceMapping(name="getCountry")
 public void getCountry(ResourceRequest request, ResourceResponse response)throws PortletException, IOException{
  System.out.println("entered getCountry");
  PrintWriter out = response.getWriter();
  out.print("return country list");
  
 }
 
 @ResourceMapping(name="getState")
 public void getState(ResourceRequest request, ResourceResponse response)throws PortletException, IOException{
  System.out.println("entered getState");
  PrintWriter out = response.getWriter();
  out.print("return state list");
  
 }

}

In the JSP added the following tags to form an URL to these annotated method. The value passed in the param with name javax.portlet.serveResource should match the annotation name variable of the method. (As we do in the processAction annotation)



<portlet:resourceURL var="getCountryURL">
 <portlet:param name="javax.portlet.serveResource" value="getCountry" />
</portlet:resourceURL>
<portlet:resourceURL var="getStateURL">
 <portlet:param name="javax.portlet.serveResource" value="getState" />
</portlet:resourceURL>

Voila it works !!