Servant portlets
Purpose
Provide ability to construct portlets that display other portlets within them. This is a carryover of a concenpt of Serant Channels from uPortal2. A client (master) portlet can request for an instance of a servant portlet based on the portlet functional name. uPortal3 framework provides simple facilities for obtaining content rendering of the servant portlet,and sharing information between client and servant portlet (through common session variables).
Interfaces and utility classes
org.jasig.portal.portlet.servant.IPortletServantLocator provides two simple methods for obtaining servant instance by the client servant. locate() method can be used to obtain an existing instance, and create() method to create a new one.
The IPortletServant interface contains methods which client portlet can use to operate on the serant portlet. Most important ones being getRenderContent() and isComplete():
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); /** * Obtain servant shared attribute * @param request current portlet request * @param key attribute key * @return attribute value */ public Object getAttribute(PortletRequest request, String key); /** * Set servant shared attribute. The attribute will be accessible by the servant portlet * through {@link ServantUtil} * @param request current portlet request * @param key attribute key * @param value attribute value */ public void setAttribute(PortletRequest request, String key, Object value); /** * Render servant portlet into the current response. * Note: as this method renders directly to the response output stream, it is recommended * to use getRenderContent method instead (see below), and incorporate portlet content into * the overall portlet rendering manually. * @param request current portlet request * @param response current portlet reponse * @throws PortletException * @throws IOException */ public void render(RenderRequest request, RenderResponse response) throws PortletException, IOException; /** * Initiate action processing on the servant portlet. * Note: the use of this method is not recommended. Servant portlet would normally process the portlet action requests * through the usual means (i.e. if an action request for the servant portlet comes in with the incoming HttpServletRequest). * Calling this method (during client portlet action or render request processing) goes against JSR168 spec (but technically, works). * @param actionRequestParameterMap * @param request * @param response */ public void processAction(Map actionRequestParameterMap, ActionRequest request, ActionResponse response); /** * Obtain content of the servant portlet for the current request. * @param request current portlet render request * @return content of the servant portlet */ public IPortletRenderContent getRenderContent(RenderRequest request, RenderResponse response); }
The servant portlet can use of the ServantUtil class to obtain information and communicate with the client portlet. Here are the method signatures:
public static boolean isServantMode(PortletRequest request) public static String getClientId(PortletRequest request) public static boolean isClientInitiatedServantActionRequest(HttpServletRequest request) public static void setAttribute(PortletRequest request, String key, Object value) public static Object getAttribute(PortletRequest request, String key) public static void setServantDone(PortletRequest request)
Sample usage
An example of servant usage is given in PortletManagers' CategoriesWizardPage. Here are the important lines:
IPortletServantLocator servantLocator = ServantLocatorAccessor.getPortletServantLocator(context); IPortletServant servant = servantLocator.locate(this.groupsServantFunctionalName, request,true); if (servant.isComplete(request)) { IGroupMember[] categoryGroups = (IGroupMember[]) servant.getAttribute(request,"servantResult"); // switch to to the next screen } PortletSession session = request.getPortletSession(); IGroupMember[] categoryGroups = (IGroupMember[])session.getAttribute(PortletDefinitionWizard.PARAM_CATEGORY_GROUPS); servant.setAttribute(request, "groupMembers", categoryGroups); servant.setAttribute(request,"allowEntitySelect",false); servant.render(request, response);