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<String, Object> createContextMap(Map<String, Object> requestMap,
Map<String, String> parameterMap,
Map<String, Object> sessionMap,
Map<String, Object> applicationMap,
PortletRequest request,
PortletResponse response,
HttpServletRequest servletRequest,
HttpServletResponse servletResponse,
ServletContext servletContext,
PortletConfig portletConfig,
Integer phase) throws IOException {
// TODO Must put http request/response objects into map for use with
container.inject(servletRequest);
// ServletActionContext
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, servletRequest);
extraContext.put(StrutsStatics.HTTP_RESPONSE, servletResponse);
extraContext.put(StrutsStatics.SERVLET_CONTEXT, servletContext);
// 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 portletRequest,
HttpServletRequest servletRequest) {
ActionMapping mapping = null;
String actionPath = null;
if (resetAction(portletRequest)) {
mapping = (ActionMapping) actionMap.get(portletRequest.getPortletMode());
} else {
actionPath = servletRequest.getParameter(ACTION_PARAM);
if (StringUtils.isEmpty(actionPath)) {
mapping = (ActionMapping) actionMap.get(portletRequest
.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
mapping = actionMapper.getMapping(servletRequest, 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<String, String> getParameterMap(PortletRequest request) throws IOException {
return new HashMap< String, String[] >(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);
}
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(actionMap, cfg, PortletMode.VIEW, "viewNamespace",
"defaultViewAction");
parseModeConfig(actionMap, cfg, PortletMode.EDIT, "editNamespace",
"defaultEditAction");
parseModeConfig(actionMap, cfg, PortletMode.HELP, "helpNamespace",
"defaultHelpAction");
parseModeConfig(actionMap, cfg, new PortletMode("config"), "configNamespace",
"defaultConfigAction");
parseModeConfig(actionMap, cfg, new PortletMode("about"), "aboutNamespace",
"defaultAboutAction");
parseModeConfig(actionMap, cfg, new PortletMode("print"), "printNamespace",
"defaultPrintAction");
parseModeConfig(actionMap, cfg, new PortletMode("preview"), "previewNamespace",
"defaultPreviewAction");
parseModeConfig(actionMap, cfg, new PortletMode("edit_defaults"),
"editDefaultsNamespace", "defaultEditDefaultsAction");
if (StringUtils.isEmpty(portletNamespace)) {
portletNamespace = "";
}
LocalizedTextUtil
.addDefaultResourceBundle("org/apache/struts2/struts-messages");
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 |
void parseModeConfig(Map<PortletMode, ActionMapping> actionMap,
PortletConfig portletConfig,
PortletMode portletMode,
String nameSpaceParam,
String defaultActionParam) {
String namespace = portletConfig.getInitParameter(nameSpaceParam);
if (StringUtils.isEmpty(namespace)) {
namespace = "";
}
modeMap.put(portletMode, namespace);
String defaultAction = portletConfig
.getInitParameter(defaultActionParam);
String method = null;
if (StringUtils.isEmpty(defaultAction)) {
defaultAction = DEFAULT_ACTION_NAME;
}
if(defaultAction.indexOf('!') >= 0) {
method = defaultAction.substring(defaultAction.indexOf('!') + 1);
defaultAction = defaultAction.substring(0, defaultAction.indexOf('!'));
}
StringBuffer fullPath = new StringBuffer();
if (StringUtils.isNotEmpty(portletNamespace)) {
fullPath.append(portletNamespace);
}
if (StringUtils.isNotEmpty(namespace)) {
fullPath.append(namespace).append("/");
} else {
fullPath.append("/");
}
fullPath.append(defaultAction);
ActionMapping mapping = new ActionMapping();
mapping.setName(getActionName(fullPath.toString()));
mapping.setNamespace(getNamespace(fullPath.toString()));
if(method != null) {
mapping.setMethod(method);
}
actionMap.put(portletMode, mapping);
}
Parse the mode to namespace mappings configured in portlet.xml |
public void processAction(ActionRequest request,
ActionResponse response) throws PortletException, IOException {
LOG.debug("Entering processAction");
resetActionContext();
try {
serviceAction(request, response, 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, 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,
Map<String, Object> requestMap,
Map<String, String> parameterMap,
Map<String, Object> sessionMap,
Map<String, Object> applicationMap,
String portletNamespace,
Integer phase) throws PortletException {
LOG.debug("serviceAction");
Dispatcher.setInstance(dispatcherUtils);
String actionName = null;
String namespace = null;
try {
ServletContext servletContext = new PortletServletContext(getPortletContext());
HttpServletRequest servletRequest = new PortletServletRequest(request, getPortletContext());
HttpServletResponse servletResponse = new PortletServletResponse(response);
if(EVENT_PHASE.equals(phase)) {
servletRequest = dispatcherUtils.wrapRequest(servletRequest, servletContext);
if(servletRequest instanceof MultiPartRequestWrapper) {
// Multipart request. Request parameters are encoded in the multipart data,
// so we need to manually add them to the parameter map.
parameterMap.putAll(servletRequest.getParameterMap());
}
}
container.inject(servletRequest);
ActionMapping mapping = getActionMapping(request, servletRequest);
actionName = mapping.getName();
namespace = mapping.getNamespace();
HashMap< String, Object > extraContext = createContextMap(requestMap, parameterMap,
sessionMap, applicationMap, request, response, servletRequest, servletResponse,
servletContext, getPortletConfig(), phase);
extraContext.put(PortletActionConstants.ACTION_MAPPING, mapping);
LOG.debug("Creating action proxy for name = " + actionName
+ ", namespace = " + namespace);
ActionProxy proxy = factory.createActionProxy(namespace,
actionName, mapping.getMethod(), extraContext);
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. |