Struts JSR-168 portlet dispatcher. Similar to the WW2 Servlet dispatcher,
but adjusted to a portal environment. The portlet is configured through the portlet.xml
descriptor. Examples and descriptions follow below:
| Method from org.apache.struts2.portlet.dispatcher.Jsr168Dispatcher Detail: |
public HashMap createContextMap(Map requestMap,
Map parameterMap,
Map sessionMap,
Map applicationMap,
PortletRequest request,
PortletResponse response,
PortletConfig portletConfig,
Integer phase) throws IOException {
// TODO Must put http request/response objects into map for use with
// ServletActionContext
HttpServletResponse dummyResponse = new PortletServletResponse(response);
HttpServletRequest dummyRequest = new PortletServletRequest(request, getPortletContext());
ServletContext dummyServletContext = new PortletServletContext(getPortletContext());
if(EVENT_PHASE.equals(phase)) {
dummyRequest = dispatcherUtils.wrapRequest(dummyRequest, dummyServletContext);
}
HashMap< String,Object > extraContext = new HashMap< String,Object >();
// The dummy servlet objects. Eases reuse of existing interceptors that uses the servlet objects.
extraContext.put(StrutsStatics.HTTP_REQUEST, dummyRequest);
extraContext.put(StrutsStatics.HTTP_RESPONSE, dummyResponse);
extraContext.put(StrutsStatics.SERVLET_CONTEXT, dummyServletContext);
// End dummy servlet objects
extraContext.put(ActionContext.PARAMETERS, parameterMap);
extraContext.put(ActionContext.SESSION, sessionMap);
extraContext.put(ActionContext.APPLICATION, applicationMap);
String defaultLocale = dispatcherUtils.getContainer().getInstance(String.class, StrutsConstants.STRUTS_LOCALE);
Locale locale = null;
if (defaultLocale != null) {
locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());
} else {
locale = request.getLocale();
}
extraContext.put(ActionContext.LOCALE, locale);
extraContext.put(StrutsStatics.STRUTS_PORTLET_CONTEXT, getPortletContext());
extraContext.put(REQUEST, request);
extraContext.put(RESPONSE, response);
extraContext.put(PORTLET_CONFIG, portletConfig);
extraContext.put(PORTLET_NAMESPACE, portletNamespace);
extraContext.put(DEFAULT_ACTION_FOR_MODE, actionMap.get(request.getPortletMode()));
// helpers to get access to request/session/application scope
extraContext.put("request", requestMap);
extraContext.put("session", sessionMap);
extraContext.put("application", applicationMap);
extraContext.put("parameters", parameterMap);
extraContext.put(MODE_NAMESPACE_MAP, modeMap);
extraContext.put(PHASE, phase);
AttributeMap attrMap = new AttributeMap(extraContext);
extraContext.put("attr", attrMap);
return extraContext;
}
Merges all application and portlet attributes into a single
HashMap to represent the entire Action context. |
public void destroy() {
if (dispatcherUtils == null) {
LOG.warn("something is seriously wrong, DispatcherUtil is not initialized (null) ");
} else {
dispatcherUtils.cleanup();
}
}
|
protected ActionMapping getActionMapping(PortletRequest request) {
ActionMapping mapping = null;
String actionPath = null;
if (resetAction(request)) {
mapping = actionMap.get(request.getPortletMode());
} else {
actionPath = request.getParameter(ACTION_PARAM);
if (!TextUtils.stringSet(actionPath)) {
mapping = actionMap.get(request
.getPortletMode());
} else {
// Use the usual action mapper, but it is expecting an action extension
// on the uri, so we add the default one, which should be ok as the
// portlet is a portlet first, a servlet second
PortletServletRequest httpRequest = new PortletServletRequest(request, getPortletContext());
mapping = actionMapper.getMapping(httpRequest, dispatcherUtils.getConfigurationManager());
}
}
if (mapping == null) {
throw new StrutsException("Unable to locate action mapping for request, probably due to " +
"an invalid action path: "+actionPath);
}
return mapping;
}
Gets the namespace of the action from the request. The namespace is the
same as the portlet mode. E.g, view mode is mapped to namespace
view, and edit mode is mapped to the namespace
edit |
String getActionName(String actionPath) {
int idx = actionPath.lastIndexOf('/");
String action = actionPath;
if (idx >= 0) {
action = actionPath.substring(idx + 1);
}
return action;
}
Get the action name part of the action path. |
protected Map getApplicationMap() {
return new PortletApplicationMap(getPortletContext());
}
|
String getNamespace(String actionPath) {
int idx = actionPath.lastIndexOf('/");
String namespace = "";
if (idx >= 0) {
namespace = actionPath.substring(0, idx);
}
return namespace;
}
Get the namespace part of the action path. |
protected Map getParameterMap(PortletRequest request) throws IOException {
return new HashMap(request.getParameterMap());
}
|
protected Map getRequestMap(PortletRequest request) {
return new PortletRequestMap(request);
}
Returns a Map of all request attributes. The default implementation is to
wrap the request in a RequestMap . Override this method to
customize how request attributes are mapped. |
protected Map getSessionMap(PortletRequest request) {
return new PortletSessionMap(request);
}
Returns a Map of all session attributes. The default implementation is to
wrap the reqeust in a SessionMap . Override this method to
customize how session attributes are mapped. |
public void init(PortletConfig cfg) throws PortletException {
super.init(cfg);
LOG.debug("Initializing portlet " + getPortletName());
Map< String,String > params = new HashMap< String,String >();
for (Enumeration e = cfg.getInitParameterNames(); e.hasMoreElements(); ) {
String name = (String) e.nextElement();
String value = cfg.getInitParameter(name);
params.put(name, value);
}
// TODO: CHECK IF NEEDED (RG Portlet Refactoring Backports)
Dispatcher.setPortletSupportActive(true);
dispatcherUtils = new Dispatcher(new PortletServletContext(cfg.getPortletContext()), params);
dispatcherUtils.init();
// For testability
if (factory == null) {
factory = dispatcherUtils.getConfigurationManager().getConfiguration().getContainer().getInstance(ActionProxyFactory.class);
}
portletNamespace = cfg.getInitParameter("portletNamespace");
LOG.debug("PortletNamespace: " + portletNamespace);
parseModeConfig(cfg, PortletMode.VIEW, "viewNamespace",
"defaultViewAction");
parseModeConfig(cfg, PortletMode.EDIT, "editNamespace",
"defaultEditAction");
parseModeConfig(cfg, PortletMode.HELP, "helpNamespace",
"defaultHelpAction");
parseModeConfig(cfg, new PortletMode("config"), "configNamespace",
"defaultConfigAction");
parseModeConfig(cfg, new PortletMode("about"), "aboutNamespace",
"defaultAboutAction");
parseModeConfig(cfg, new PortletMode("print"), "printNamespace",
"defaultPrintAction");
parseModeConfig(cfg, new PortletMode("preview"), "previewNamespace",
"defaultPreviewAction");
parseModeConfig(cfg, new PortletMode("edit_defaults"),
"editDefaultsNamespace", "defaultEditDefaultsAction");
if (!TextUtils.stringSet(portletNamespace)) {
portletNamespace = "";
}
LocalizedTextUtil
.addDefaultResourceBundle("org/apache/struts2/struts-messages");
Container container = dispatcherUtils.getContainer();
//check for configuration reloading
if ("true".equalsIgnoreCase(container.getInstance(String.class, StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD))) {
FileManager.setReloadingConfigs(true);
}
actionMapper = container.getInstance(ActionMapper.class);
}
Initialize the portlet with the init parameters from portlet.xml |
public void processAction(ActionRequest request,
ActionResponse response) throws PortletException, IOException {
LOG.debug("Entering processAction");
resetActionContext();
try {
serviceAction(request, response, getActionMapping(request),
getRequestMap(request), getParameterMap(request),
getSessionMap(request), getApplicationMap(),
portletNamespace, EVENT_PHASE);
LOG.debug("Leaving processAction");
} finally {
ActionContext.setContext(null);
}
}
Service an action from the event phase. |
public void render(RenderRequest request,
RenderResponse response) throws PortletException, IOException {
LOG.debug("Entering render");
resetActionContext();
response.setTitle(getTitle(request));
if(!request.getWindowState().equals(WindowState.MINIMIZED)) {
try {
// Check to see if an event set the render to be included directly
serviceAction(request, response, getActionMapping(request),
getRequestMap(request), getParameterMap(request),
getSessionMap(request), getApplicationMap(),
portletNamespace, RENDER_PHASE);
LOG.debug("Leaving render");
} finally {
resetActionContext();
}
}
}
Service an action from the render phase. |
public void serviceAction(PortletRequest request,
PortletResponse response,
ActionMapping mapping,
Map requestMap,
Map parameterMap,
Map sessionMap,
Map applicationMap,
String portletNamespace,
Integer phase) throws PortletException {
LOG.debug("serviceAction");
String actionName = mapping.getName();
String namespace = mapping.getNamespace();
Dispatcher.setInstance(dispatcherUtils);
try {
HashMap extraContext = createContextMap(requestMap, parameterMap,
sessionMap, applicationMap, request, response,
getPortletConfig(), phase);
LOG.debug("Creating action proxy for name = " + actionName
+ ", namespace = " + namespace);
ActionProxy proxy = factory.createActionProxy(namespace,
actionName, extraContext);
proxy.setMethod(mapping.getMethod());
request.setAttribute("struts.valueStack", proxy.getInvocation()
.getStack());
proxy.execute();
} catch (ConfigurationException e) {
LOG.error("Could not find action", e);
throw new PortletException("Could not find action " + actionName, e);
} catch (Exception e) {
LOG.error("Could not execute action", e);
throw new PortletException("Error executing action " + actionName,
e);
} finally {
Dispatcher.setInstance(null);
}
}
Loads the action and executes it. This method first creates the action
context from the given parameters then loads an ActionProxy
from the given action name and namespace. After that, the action is
executed and output channels throught the response object. |
public void setActionMapper(ActionMapper actionMapper) {
this.actionMapper = actionMapper;
}
|
protected void setActionProxyFactory(ActionProxyFactory factory) {
this.factory = factory;
}
Convenience method to ease testing. |