...
If the portlet has important functions that could likely be reused by some other portlets it makes sense to use the servant mode. Based on the information received with the PortletRequest such portlets can distinguish the normal modes like VIEW,EDIT,HELP from the "servant" and perform different operations to interact with the client-portlet. To provide portlet-servant communication on the servant side ServantUtil class is used. In the following example the groups manager portlet gets the request attribute sent by the client-portlet in the servant mode:
Code Block |
---|
borderStyle | solid |
---|
title | GroupsManagerPortlet.java |
---|
borderStyle | solid |
---|
|
if ( ServantUtil.isServantMode(portletRequest) ) {
IGroupMember[] groupMembers = (IGroupMember[]) ServantUtil.getAttribute(portletRequest);
...
if ( "Done".equals(request.getParameter("grpCommand") ) {
// Return result to clients
ServantUtil.setAttribute(req,getResults(portletRequest));
// Notify clients that the servant is complete
ServantUtil.setServantDone(portletRequest);
}
}
|
...
The typical client-servant interaction from the client's point of view is shown below. Every time when the portlet's processAction() or render()" is called the client has to get the reference to the IPortletServantLocator instance and , then call _locate() to return the instance of the IPortletServant and delegate the request processing to the servant:
Code Block |
---|
borderStyle | solid |
---|
title | TestServantPortlet.java | borderStyle | solid |
---|
|
public class TestServantPortlet extends GenericPortlet {
/**
* The internal method that returns the IPortletServant instance.
*/
private IPortletServant getPortletServant(String servantFname, PortletRequest request) {
IPortletServantLocator servantLocator = ServantLocatorAccessor.getPortletServantLocator(getPortletContext());
IPortletServant servant = servantLocator.locate(servantFname,request);
return servant;
}
/**
* The implemenation of GenericPortlet's processAction() with delegating the action request processing to the servant.
*/
public void processAction(ActionRequest req, ActionResponse res) throws PortletException, IOException {
// Get the servant functional name
String servantFname = ...
if ( servantFname != null ) {
IPortletServant servant = getPortletServant(servantFname,req);
servant.processAction(req,res);
if ( servant.isComplete(req) ) {
// Get result when the servant is done
Object result = servant.getServantData(req);
...
}
}
}
...
}
|
...
Servant interfaces
Code Block |
---|
borderStyle | solid |
---|
title | ServantLocatorAccessor.java | borderStyle | solid |
---|
|
/**
* Provides methods for accessing the portlet servant locator
*/
public final class ServantLocatorAccessor {
/**
* Creates a new IPortletServantLocator instance that will be used to locate portlet servants.
**/
public static IPortletServantLocator getPortletServantLocator(PortletContext portletContext) {
return ((PortletContextWrapper)portletContext).getPortletServantLocator();
}
private ServantLocatorAccessor() { }
}
|
Code Block |
---|
borderStyle | solid |
---|
title | IPortletServantLocator.java | borderStyle | solid |
---|
|
/**
* Provides methods for locating portlet servants provided by uPortal.
*/
public interface IPortletServantLocator {
/**
* Gets a new IPortletServant instance for running the specified portlet as a servant.
* @param functionalPortletName is a portlet functional name given during portlet publising
* @param request a PortletRequest
**/
public IPortletServant locate(String functionalPortletName,PortletRequest request);
}
|
Code Block |
---|
borderStyle | solid |
---|
title | IPortletServant.java | borderStyle | solid |
---|
|
/**
* The PortletServant interface is a uPortal wrapper around a JSR-168 portlet that implements
* the Portlet Servant mode. It provides methods for delegating rendering and action processing
* to the servant portlet, exchanging attribute values with the Client Portlet, to watch for it's completion and to get the results of the servant's
* operation.
*/
public interface IPortletServant {
/**
* Returns the servant ID given by the portlet servant locator.
* @return a <code>String</code> value
*/
public String getId();
/** Allows the Client Portlet to ascertain if the Servant has accomplished the requested task
* (Note that the way which a certain task is requested is not specified by this interface;
* normally it will be documented by a particular IPortletServant and require some particular
* configuration paramaters used to initialize the servant)
* @return boolean value
*/
public boolean isComplete(PortletRequest request);
public Object getServantData(PortletRequest request);
public void setServantData(PortletRequest request,Object value);
public void render(RenderRequest request, RenderResponse response) throws PortletException, IOException;
public void processAction(ActionRequest request, ActionResponse response) throws PortletException, java.io.IOException;
}
|
Servant-side utilities
Code Block |
---|
borderStyle | solid |
---|
title | ServantUtil.java |
---|
borderStyle | solid |
---|
|
/**
* The utility class that provides a portlet with the servant-side methods methods.
*
* @author Michael Ivanov, mivanov at unicon.net
* @version $Revision: 1.1 $
*
*/
public final class ServantUtil {
public static boolean isServantMode(PortletRequest request) {
return (InternalServantUtil.getServantId(request)!=null);
}
public static boolean isServantMode(HttpServletRequest request) {
return (InternalServantUtil.getServantId(request)!=null);
}
public static void setAttribute(PortletRequest request, Object value) {
InternalServantUtil.setAttribute(InternalServantUtil.getServantId(request),request,value);
}
public static Object getAttribute(PortletRequest request) {
return InternalServantUtil.getAttribute(InternalServantUtil.getServantId(request),request);
}
public static void setServantDone(PortletRequest request) {
request.setAttribute(InternalServantUtil.getServantDoneKey(InternalServantUtil.getServantId(request)),"true");
}
private ServantUtil() {}
}
|
Code Block |
---|
borderStyle | solid |
---|
title | InternalServantUtil.java | borderStyle | solid |
---|
|
/**
*
* The internal class containing static methods used by the framework to provide client-servant communication .
*
* @author Michael Ivanov, mivanov at unicon.net
* @version $Revision: 1.4 $
*
*/
public final class InternalServantUtil {
private static final String PORTLET_SERVANT_DONE = "javax.portlet.servant.done.";
private static final String PORTLET_SERVANT_ATTRIBUTE = "javax.portlet.servant.attribute.";
private static final String SERVANT_ID_PARAMETER_NAME = "javax.portlet.servant.id";
public static String getServantId(PortletRequest request) {
return request.getParameter(SERVANT_ID_PARAMETER_NAME);
}
public static String getServantId(HttpServletRequest request) {
return request.getParameter(SERVANT_ID_PARAMETER_NAME);
}
private static String getServantAttributeKey(String servantId) {
return PORTLET_SERVANT_ATTRIBUTE + servantId;
}
protected static String getServantDoneKey(String servantId) {
return PORTLET_SERVANT_DONE + servantId;
}
protected static void setAttribute(String servantId, PortletRequest request, Object value) {
request.setAttribute(getServantAttributeKey(servantId),value);
}
protected static Object getAttribute(String servantId, PortletRequest request) {
return request.getAttribute(getServantAttributeKey(servantId));
}
public static boolean isServantDone(String servantId, ServletRequest request) {
return (request.getAttribute(getServantDoneKey(servantId))!=null);
}
public static boolean isServantDone(String servantId, PortletRequest request) {
return (request.getAttribute(getServantDoneKey(servantId))!=null);
}
public static HttpServletRequest prepareServantServletRequest(String servantId, HttpServletRequest request) {
PortletHttpServletRequestWrapper wrappedRequest = new PortletHttpServletRequestWrapper(request);
Map requestParams = new HashMap();
if ( request.getParameterMap() != null ) {
requestParams.putAll(request.getParameterMap());
}
requestParams.put(SERVANT_ID_PARAMETER_NAME,new String[] {servantId});
wrappedRequest.setParameterValueMap(requestParams);
return wrappedRequest;
}
private InternalServantUtil() {}
}
|