001: /*
002: * (C) Copyright 2004 Nabh Information Systems, Inc.
003: *
004: * All copyright notices regarding Nabh's products MUST remain
005: * intact in the scripts and in the outputted HTML.
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public License
008: * as published by the Free Software Foundation; either version 2.1
009: * of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: */
021: package com.nabhinc.portlet.mvcportlet.core;
022:
023: import java.io.IOException;
024: import java.net.URLEncoder;
025: import java.util.Enumeration;
026: import java.util.HashMap;
027: import java.util.Iterator;
028: import java.util.List;
029: import java.util.Locale;
030: import java.util.Map;
031: import java.util.Set;
032: import java.util.Vector;
033:
034: import javax.portlet.ActionRequest;
035: import javax.portlet.ActionResponse;
036: import javax.portlet.Portlet;
037: import javax.portlet.PortletConfig;
038: import javax.portlet.PortletContext;
039: import javax.portlet.PortletException;
040: import javax.portlet.PortletMode;
041: import javax.portlet.PortletRequest;
042: import javax.portlet.PortletResponse;
043: import javax.portlet.PortletSecurityException;
044: import javax.portlet.PortletSession;
045: import javax.portlet.RenderRequest;
046: import javax.portlet.RenderResponse;
047: import javax.portlet.WindowState;
048:
049: import com.nabhinc.core.MimeTypes;
050: import com.nabhinc.portlet.common.CommonUtil;
051: import com.nabhinc.condition.Condition;
052: import com.nabhinc.util.StringUtil;
053: import org.apache.commons.fileupload.FileUploadException;
054:
055: /**
056: * Main controller class that handles all incoming <code>processAction</code>
057: * and <code>render</code> requests.
058: *
059: * @author Padmanabh Dabke
060: * (c) 2004 Nabh Information Systems, Inc. All Rights Reserved.
061: */
062: public class ControllerPortlet implements Portlet {
063:
064: /**
065: * Cached portlet context
066: */
067: private PortletContext cpContext = null;
068:
069: /**
070: * Portlet configuation
071: */
072: protected ControllerPortletConfig cpConfig = null;
073:
074: /**
075: * Map of render processor names -> render processors
076: */
077: private HashMap cpRenderProcessorMap = new HashMap();
078:
079: /**
080: * Map of action processor names -> action processors
081: */
082: private HashMap cpActionProcessorMap = new HashMap();
083:
084: /**
085: * Map of request types -> RenderConfig objects
086: */
087: private HashMap cpRenderConfigMap = new HashMap();
088:
089: /**
090: * Map of portlet modes -> default render types
091: */
092: private HashMap cpDefaultRenderTypes = new HashMap();
093:
094: /**
095: * Map of request types -> ActionConfig objects
096: */
097: private HashMap cpActionConfigMap = new HashMap();
098:
099: /**
100: * Map of portlet modes -> default action types
101: */
102: private String cpDefaultActionType = null;
103:
104: /**
105: * Directory for storing uploaded files temporarily
106: */
107: private String cpUploadTempDir = null;
108:
109: /**
110: * Map from Locale -> path for that locale
111: */
112: private HashMap cpLocalizedPaths = new HashMap();
113:
114: /**
115: * ControllerPortlet initialization mainly consists of reading portlet
116: * configuration files and constructing instances of all supporting
117: * class needed for portlet operation. ControllerPortlet expects at
118: * least one parameter "configFile" in it's portlet configuration
119: * defined in "portlet.xml" file. The value of this parameter must be
120: * the context relative path for the portlet configuration file. In
121: * addition, you can also specifiy "messageFile". This parameter
122: * specifies the location of the file that defines internationalized
123: * message strings. If this path starts with a "/", then it is assumed
124: * to be relative to the Web application root directory. Otherwise, it
125: * is assumed to be in the same location as portlet
126: * configuration file.
127: * @param config Portlet configuration
128: * @throws PortletException
129: */
130: public void init(PortletConfig config) throws PortletException {
131:
132: // Cache portlet context
133: cpContext = config.getPortletContext();
134:
135: // Read portlet configuation
136: cpConfig = new ControllerPortletConfig();
137: cpConfig.init(config);
138:
139: // Cache some of the maps for efficiency
140: cpRenderProcessorMap = cpConfig.getRenderProcessorMap();
141: cpActionProcessorMap = cpConfig.getActionProcessorMap();
142: cpRenderConfigMap = cpConfig.getRenderConfigMap();
143: cpDefaultRenderTypes = cpConfig.getDefaultRenderTypes();
144: cpActionConfigMap = cpConfig.getActionConfigMap();
145: cpDefaultActionType = cpConfig.getDefaultActionType();
146: cpUploadTempDir = cpConfig.getUploadTempDir();
147: }
148:
149: /**
150: * This method handles portlet render requests in "view" mode. Please see
151: * MVCPortlet user guide for details about this method.
152: */
153: public void render(RenderRequest request, RenderResponse response)
154: throws PortletException, IOException {
155:
156: response.setContentType(getRenderContentType(request));
157:
158: // Extra parameters passed to include dispatch
159: String includeParams = "";
160:
161: // Determine render type
162: RenderConfig renderConfig = null;
163: String renderType = request
164: .getParameter(Constants.REQUEST_TYPE_PARAM);
165:
166: String portletMode = request.getPortletMode().toString()
167: .toLowerCase();
168: if (renderType == null) {
169: renderType = (String) cpDefaultRenderTypes.get(portletMode);
170: }
171:
172: if (renderType == null) {
173: throw new PortletException("Unspecified render type.");
174: }
175:
176: // Find render configuration for this request type
177: renderConfig = getRenderConfig(request, renderType);
178: if (renderConfig == null) {
179: renderType = (String) cpDefaultRenderTypes.get(portletMode);
180: renderConfig = getRenderConfig(request, renderType);
181: }
182:
183: if (renderConfig == null)
184: throw new PortletException("Unrecognized render type: "
185: + renderType);
186:
187: // Check if the user has permission to access this view
188: if (!checkPermission(renderType, request, response,
189: renderConfig.getPrecondition())) {
190: throw new PortletSecurityException("Action not permitted");
191: }
192:
193: // Insert navigation node corresponding to this render type
194: addNavNode(renderConfig.getNavigationNode(), request, response,
195: portletMode, renderType);
196:
197: // Set attributes pointing to this instance of ControllerPortlet
198: // and RenderConnfig for the request.
199: request.setAttribute(Constants.PORTLET_CONFIG_ATTRIB, cpConfig);
200: request.setAttribute(Constants.RENDER_CONFIG_ATTRIB,
201: renderConfig);
202:
203: // Process logic common to all view types
204: preprocessRender(request, response);
205:
206: // Check if there is a processor associated with this request type
207: RenderProcessor processor = renderConfig.getRenderProcessor();
208:
209: // If there is a form associated with this request type, set the
210: // corresponding attribute
211: if (processor != null) {
212: Form form = renderConfig.getForm();
213: if (form != null) {
214: request.setAttribute(Constants.FORM_ATTRIB, form);
215: }
216: }
217: String includePath = null;
218: if (processor != null) {
219: includePath = computeIncludePath(request, response,
220: renderConfig);
221: }
222:
223: // If include path is not set, check if there is a default include path
224: // for this request type
225: if (includePath == null)
226: includePath = renderConfig.getDefaultIncludePath(request);
227:
228: // Include display
229: if (includePath != null) {
230: includePath = getLocalizedPath(includePath, request
231: .getLocale());
232: cpContext.getRequestDispatcher(includePath + includeParams)
233: .include(request, response);
234: }
235:
236: }
237:
238: /**
239: * Process action method is typically called when a user submits a form, or clicks
240: * on a link corresponding to an ActionURL. Please see MVCPortlet user guide for a
241: * detailed description of this method implementation.
242: * @param request
243: * @param response
244: * @throws PortletException
245: * @throws IOException
246: */
247: public void processAction(ActionRequest request,
248: ActionResponse response) throws PortletException,
249: IOException {
250:
251: String requestType = null;
252: String portletMode = request.getPortletMode().toString()
253: .toLowerCase();
254: // Determine action type
255: String actionType = request
256: .getParameter(Constants.REQUEST_TYPE_PARAM);
257: if (actionType == null)
258: actionType = cpDefaultActionType;
259: if (actionType == null) {
260: throw new PortletException(
261: "Cannot resolve request type in processAction.");
262: }
263:
264: ActionConfig actionConfig = (ActionConfig) cpActionConfigMap
265: .get(actionType);
266: if (actionConfig == null) {
267: throw new PortletException("Invalid action type");
268: }
269:
270: // Check if the user has permission to invoke this action
271: boolean isPermissioned = checkPermission(actionType, request,
272: response, actionConfig.getPrecondition());
273: if (!isPermissioned) {
274: throw new PortletSecurityException("Action not permitted.");
275: }
276:
277: // Find a processor and possibly a form for this action
278: Form form = actionConfig.getForm();
279: ActionProcessor processor = actionConfig.getActionProcessor();
280:
281: boolean success = true;
282:
283: // Wrap original request if this is a file upload submission.
284: String contentType = request.getContentType();
285: if (contentType != null
286: && contentType.startsWith("multipart/form-data")
287: && actionConfig.isWrapMultipart()) {
288:
289: try {
290: MultipartRequestWrapper requestWrapper = new MultipartRequestWrapper(
291: request, actionConfig.getMaxFileSize(),
292: actionConfig.getThreshold(), cpUploadTempDir);
293: request = requestWrapper;
294:
295: } catch (FileUploadException fue) {
296: success = false;
297: response.setRenderParameter(
298: Constants.ERROR_MESSAGE_PARAM + portletMode,
299: fue.getMessage());
300: ProcessorResult errorResult = actionConfig
301: .getProcessorResult("",
302: Constants.FILE_UPLOAD_ERROR_KEY);
303: if (errorResult == null) {
304: throw new PortletException(
305: "Action includes file upload, but file-upload-error is not configured.");
306: }
307: requestType = processActionResult(request, response,
308: errorResult, actionConfig, portletMode);
309: }
310: }
311:
312: // Process logic common to all action types
313: if (success)
314: preprocessAction(request, response);
315:
316: if (success
317: && request.getParameter(Constants.CANCEL_PARAM) != null) {
318: if (form != null)
319: form.cancel(request, response);
320: String cancelKey = processor.cancel(request, response);
321: removeLastNavNode(request, portletMode);
322: success = false;
323: ProcessorResult cancelResult = actionConfig
324: .getProcessorResult("", cancelKey);
325: if (cancelResult == null) {
326: throw new PortletException(
327: "Action includes form cancellation, but cancel is not configured.");
328: }
329: requestType = processActionResult(request, response,
330: cancelResult, actionConfig, portletMode);
331: }
332:
333: if (success) {
334: if (form != null && actionConfig.isValidateForm()) {
335: success = form.validate(request, response,
336: actionConfig, this );
337: if (!success) {
338: ProcessorResult errorResult = actionConfig
339: .getProcessorResult("",
340: Constants.VALIDATION_ERROR_KEY);
341: if (errorResult == null) {
342: throw new PortletException(
343: "Action includes form validation, but validation-error is not configured.");
344: }
345: requestType = processActionResult(request,
346: response, errorResult, actionConfig,
347: portletMode);
348: }
349: }
350: }
351:
352: // Form validation was successful, forward the call to ActionProcessor(s).
353: if (success) {
354: // Not checking if processor is null because that should be
355: // ensured by ControllerPortlet during initialization.
356: String resultKey = processor.process(request, response,
357: actionConfig);
358: if (resultKey == null) {
359: throw new PortletException(
360: "Action processor for request type "
361: + actionType + " returned null.");
362: }
363: ProcessorResult result = actionConfig.getProcessorResult(
364: processor.getName(), resultKey);
365: if (result == null) {
366: throw new PortletException(
367: "Action processor for request type "
368: + actionType
369: + " returned invalid result key: "
370: + resultKey + ".");
371: }
372: requestType = processActionResult(request, response,
373: result, actionConfig, portletMode);
374: }
375:
376: // If the action was successful, pop the extra nodes from the node path
377: // This no longer needs to be done. We are checking for existing
378: // Node states in the render phase.
379: /*
380: if (success) {
381: RenderConfig renderConfig = getRenderConfig(request, requestType);
382: if (renderConfig != null && renderConfig.getNavigationNode() != null)
383: popNodes(renderConfig.getNavigationNode(), request, portletMode);
384: }
385: */
386: if (requestType != null) {
387: response.setRenderParameter(Constants.REQUEST_TYPE_PARAM,
388: requestType);
389: response.setRenderParameter(
390: Constants.POST_USER_ACTION_PARAM
391: + (form != null ? form.getName() : ""),
392: "true");
393:
394: }
395:
396: }
397:
398: private String computeIncludePath(RenderRequest request,
399: RenderResponse response, RenderConfig renderConfig)
400: throws PortletException, IOException {
401:
402: String includePath = renderConfig
403: .getDefaultIncludePath(request);
404: RenderProcessor processor = renderConfig.getRenderProcessor();
405:
406: while (processor != null) {
407:
408: String resultKey = processor.process(request, response,
409: renderConfig);
410: ProcessorResult result = null;
411: if (resultKey != null) {
412: result = renderConfig.getProcessorResult(processor
413: .getName(), resultKey);
414: }
415:
416: if (result == null) {
417: if (resultKey == null)
418: includePath = renderConfig
419: .getDefaultIncludePath(request);
420: else
421: includePath = renderConfig.getIncludePath(request,
422: resultKey);
423: break;
424: }
425:
426: if (result.getType() == ProcessorResult.TYPE_RENDER) {
427: includePath = renderConfig.getIncludePath(request,
428: result.getValue());
429: break;
430: } else if (result.getType() == ProcessorResult.TYPE_PROCESS) {
431: processor = (RenderProcessor) cpRenderProcessorMap
432: .get(result.getValue());
433: } else {
434: throw new PortletException(
435: "Invalid render result type.");
436: }
437: }
438: return includePath;
439: }
440:
441: private String processActionResult(ActionRequest request,
442: ActionResponse response, ProcessorResult result,
443: ActionConfig actionConfig, String portletMode)
444: throws PortletException, IOException {
445:
446: while (true) {
447: switch (result.getType()) {
448: case ProcessorResult.TYPE_RENDER:
449: // Check if this action is associated with a status message
450: MessageInfo mInfo = result.getMessageInfo();
451: if (result.getPortletMode() != null) {
452: portletMode = result.getPortletMode();
453: response.setPortletMode(new PortletMode(result
454: .getPortletMode()));
455: }
456: if (result.getWindowState() != null) {
457: response.setWindowState(new WindowState(result
458: .getWindowState()));
459: }
460: if (mInfo != null) {
461: setMessageParameter(response, mInfo, portletMode);
462: }
463: // Transfer action parameters to render request
464: boolean transferParams = actionConfig
465: .isSetRenderParameters();
466: String setR = result.getSetRenderParameters();
467: if ("true".equals(setR))
468: transferParams = true;
469: else if ("false".equals(setR))
470: transferParams = false;
471: if (transferParams) {
472: transferRenderParameters(request, response,
473: actionConfig, actionConfig.getForm(),
474: result.getParams());
475: }
476:
477: return result.getValue();
478: case ProcessorResult.TYPE_REDIRECT:
479: String redirect = result.getValue();
480: if (StringUtil.isNotNullOrEmpty(redirect)) {
481: if (redirect.startsWith("/")) {
482: redirect = request.getContextPath() + redirect;
483: }
484: processRedirect(request, response, redirect);
485: }
486: return null;
487: case ProcessorResult.TYPE_PROCESS:
488: ActionProcessor processor = (ActionProcessor) cpActionProcessorMap
489: .get(result.getValue());
490: if (processor == null) {
491: throw new PortletException(
492: "Invalid processor name: "
493: + result.getValue());
494: }
495: String resultKey = processor.process(request, response,
496: actionConfig);
497: if (resultKey == null) {
498: throw new PortletException(
499: "Action processor for request type "
500: + result.getValue()
501: + " returned null.");
502: }
503: result = actionConfig.getProcessorResult(processor
504: .getName(), resultKey);
505: if (result == null) {
506: throw new PortletException(
507: "Invalid result action key: " + resultKey
508: + ".");
509: }
510: break;
511: }
512: }
513:
514: }
515:
516: /**
517: * This request marks the end of the life cycle of the portlet. The method
518: * calls destroy method on all registered ActionProcessor and RenderProcessor
519: * objects.
520: */
521: public void destroy() {
522:
523: // Call destroy method on all render processors.
524: Iterator iter = cpRenderConfigMap.values().iterator();
525: while (iter.hasNext()) {
526: try {
527: RenderProcessor processor = ((RenderConfig) iter.next())
528: .getRenderProcessor();
529: if (processor != null)
530: processor.destroy();
531: } catch (Exception ex) {
532: // Ignore
533: }
534: }
535:
536: // Call destroy method on all action processors
537: iter = cpActionConfigMap.values().iterator();
538: while (iter.hasNext()) {
539: try {
540: ActionProcessor processor = ((ActionConfig) iter.next())
541: .getActionProcessor();
542: if (processor != null)
543: processor.destroy();
544:
545: } catch (Exception ex) {
546: // Ignore
547: }
548: }
549: }
550:
551: /**
552: * This method is invoked before passing a portlet request to
553: * an view handler. The default implementation is empty.
554: * <p/>Portlet subclasses should
555: * override this method to implement preprocessing common
556: * to all view types.
557: *
558: * @param request
559: * @param response
560: */
561: public void preprocessRender(RenderRequest request,
562: RenderResponse response) throws PortletException {
563: }
564:
565: /**
566: * This method is invoked before passing a portlet request to
567: * an action processor. The default implementation is empty
568: * <p/>Portlet subclasses should
569: * override this method to implement preprocessing common
570: * to all actions. If you encounters errors in this call,
571: * you should wrap the exception in a PortletException and throw.
572: * @param request
573: * @param response
574: */
575: public void preprocessAction(ActionRequest request,
576: ActionResponse response) throws PortletException {
577: return;
578: }
579:
580: /**
581: *
582: * @param mode Portlet mode
583: * @param request Render or action request
584: * @param response Render or action responze
585: * @param precon Precondition that must be satisfied to have access
586: * @return
587: * @throws PortletException
588: */
589: private boolean checkPermission(String mode,
590: PortletRequest request, PortletResponse response,
591: Condition precon) throws PortletException {
592:
593: try {
594: if (precon == null)
595: return true;
596: return precon.isSatisfied(request, mode);
597: } catch (Exception ex) {
598: throw new PortletException(
599: "Error in checking portlet permission.", ex);
600: }
601:
602: }
603:
604: private void setMessageParameter(ActionResponse response,
605: MessageInfo mInfo, String pMode) {
606: String param = Constants.SUCCESS_MESSAGE_PARAM;
607: switch (mInfo.getType()) {
608: case Constants.MESSAGE_TYPE_SUCCESS:
609: break;
610: case Constants.MESSAGE_TYPE_ALERT:
611: param = Constants.ALERT_MESSAGE_PARAM;
612: break;
613: case Constants.MESSAGE_TYPE_ERROR:
614: param = Constants.ERROR_MESSAGE_PARAM;
615: break;
616: case Constants.MESSAGE_TYPE_INFO:
617: param = Constants.INFO_MESSAGE_PARAM;
618: break;
619: case Constants.MESSAGE_TYPE_STATUS:
620: param = Constants.STATUS_MESSAGE_PARAM;
621: break;
622: }
623: response.setRenderParameter(param + pMode, mInfo.getKey());
624: }
625:
626: @SuppressWarnings({"unchecked","unchecked"})
627: private void addNavNode(NavigationNode node, RenderRequest req,
628: RenderResponse resp, String pMode, String renderType) {
629: if (node == null)
630: return;
631: NavigationNodeState navState = new NavigationNodeState(req,
632: resp, node, renderType);
633: if (req.getParameter(Constants.POP_NODES_PARAM) != null) {
634: popNodes(navState, req, pMode);
635: return;
636: }
637: PortletSession session = req.getPortletSession();
638: Vector nodeVec = (Vector) session
639: .getAttribute(Constants.NAV_PATH_ATTRIB + pMode);
640: if (nodeVec == null) {
641: nodeVec = new Vector(5);
642: session.setAttribute(Constants.NAV_PATH_ATTRIB + pMode,
643: nodeVec);
644: }
645:
646: if (node.isResetPath()
647: || req.getParameter(Constants.RESET_NAV_NODE_PARAM) != null) {
648: nodeVec.clear();
649: nodeVec.addElement(navState);
650: return;
651: }
652:
653: if (nodeVec.size() > 0) {
654: // Check if we have already visited this node. If so don't add it
655: int size = nodeVec.size();
656: for (int i = 0; i < size; i++) {
657: NavigationNodeState existingNode = (NavigationNodeState) nodeVec
658: .elementAt(i);
659: if (existingNode.compare(navState)) {
660: i++;
661: int j = i;
662: while (j < size) {
663: nodeVec.remove(i);
664: j++;
665: }
666: return;
667: }
668: }
669: /*
670: NavigationNodeState lastNode = (NavigationNodeState) nodeVec.elementAt(nodeVec.size()-1);
671: if (lastNode.compare(navState)) return;
672: */
673: }
674: nodeVec.addElement(navState);
675: }
676:
677: private void removeLastNavNode(PortletRequest req, String pMode) {
678: PortletSession session = req.getPortletSession();
679: Vector nodeVec = (Vector) session
680: .getAttribute(Constants.NAV_PATH_ATTRIB + pMode);
681: if (nodeVec == null || nodeVec.size() == 0)
682: return;
683: nodeVec.removeElementAt(nodeVec.size() - 1);
684: }
685:
686: private void popNodes(NavigationNodeState node, PortletRequest req,
687: String pMode) {
688: PortletSession session = req.getPortletSession();
689: Vector nodeVec = (Vector) session
690: .getAttribute(Constants.NAV_PATH_ATTRIB + pMode);
691: if (nodeVec == null)
692: return;
693:
694: int len = nodeVec.size();
695: int curPos = 99999999;
696: for (int i = 0; i < len; i++) {
697: if (((NavigationNodeState) nodeVec.elementAt(i))
698: .compare(node)) {
699: curPos = i;
700: break;
701: }
702: }
703: for (int i = len - 1; i > curPos; i--) {
704: nodeVec.removeElementAt(i);
705: }
706: return;
707: }
708:
709: private RenderConfig getRenderConfig(PortletRequest request,
710: String renderType) throws PortletException {
711: String portletMode = request.getPortletMode().toString()
712: .toLowerCase();
713: if (renderType == null) {
714: renderType = (String) cpDefaultRenderTypes.get(portletMode);
715: }
716:
717: if (renderType == null) {
718: throw new PortletException("Unspecified render type.");
719: }
720:
721: // Find render configuration for this request type
722: HashMap renderConfigMap = (HashMap) cpRenderConfigMap
723: .get(portletMode);
724: if (renderConfigMap == null)
725: throw new PortletException("Unsupported portlet mode: "
726: + portletMode);
727: return (RenderConfig) renderConfigMap.get(renderType);
728: }
729:
730: // This method copies all parameters in the supplied map to the response. The method
731: // does this manually instead of calling response.setParameters(Map) method to
732: // preserve any render parameters that may have been set by an action processor.
733: private void setRenderParameters(ActionRequest request,
734: ActionResponse response, String params) {
735: if (StringUtil.isNotNullOrEmpty(params)) {
736: String[] paramsArray = StringUtil.split(params, ",");
737: for (int i = 0; i < paramsArray.length; i++) {
738: String paramName = paramsArray[i];
739: String[] paramValues = request
740: .getParameterValues(paramName);
741: response.setRenderParameter(paramName, paramValues);
742:
743: }
744: } else {
745: Map paramMap = request.getParameterMap();
746: Set entries = paramMap.entrySet();
747: for (Iterator iter = entries.iterator(); iter.hasNext();) {
748: Map.Entry element = (Map.Entry) iter.next();
749: try {
750: String paramName = (String) element.getKey();
751: String[] paramValues = (String[]) element
752: .getValue();
753: response.setRenderParameter(paramName, paramValues);
754: } catch (ClassCastException ex) {
755: throw new IllegalArgumentException(
756: "Parameter map keys must be strings and the values must be string arrays.");
757: }
758:
759: }
760: }
761:
762: }
763:
764: private void transferRenderParameters(ActionRequest request,
765: ActionResponse response, ActionConfig actionConfig,
766: Form form, String params) {
767: int scope = Constants.SCOPE_REQUEST;
768: if (actionConfig.getScope() != Constants.SCOPE_UNSPECIFIED) {
769: scope = actionConfig.getScope();
770: } else if (form != null
771: && form.getScopeAsInt() != Constants.SCOPE_UNSPECIFIED) {
772: scope = form.getScopeAsInt();
773: }
774: int sessionScope = PortletSession.APPLICATION_SCOPE;
775: switch (scope) {
776: case Constants.SCOPE_REQUEST:
777: // response.setRenderParameters(request.getParameterMap());
778: setRenderParameters(request, response, params);
779: break;
780: case Constants.SCOPE_PORTLET_SESSION:
781: sessionScope = PortletSession.PORTLET_SCOPE;
782: // Fall through
783: case Constants.SCOPE_APPLICATION_SESSION:
784: setSessionScopeAttribute(request, response, form,
785: sessionScope, params);
786: break;
787: case Constants.SCOPE_PORTLET_CONTEXT:
788: setPortletContextScopeAttribute(request, response, form,
789: params);
790: }
791:
792: }
793:
794: private void setSessionScopeAttribute(ActionRequest request,
795: ActionResponse response, Form form, int sessionScope,
796: String paramStr) {
797: PortletSession ses = request.getPortletSession();
798: if (StringUtil.isNotNullOrEmpty(paramStr)) {
799: String[] paramsArray = StringUtil.split(paramStr, ",");
800: for (int i = 0; i < paramsArray.length; i++) {
801: String paramName = paramsArray[i];
802: setSessionAttribute(request, ses, paramName,
803: sessionScope);
804: }
805: } else {
806: // Set session attributes under appropriate scope
807: if (form == null) {
808: // Tranfer all request parameters as session attributes
809: Enumeration params = request.getParameterNames();
810: while (params.hasMoreElements()) {
811: String paramName = (String) params.nextElement();
812: setSessionAttribute(request, ses, paramName,
813: sessionScope);
814: }
815: } else {
816: // If we have a form, we only set parameters that are part of
817: // the form. We need to revisit this decision after we get more
818: // examples of the usage of this feature
819: List fieldList = form.getFieldList();
820: for (int i = 0; i < fieldList.size(); i++) {
821: FormField field = (FormField) fieldList.get(i);
822: String paramName = field.getName();
823: setSessionAttribute(request, ses, paramName,
824: sessionScope);
825: }
826: }
827: }
828: }
829:
830: private void setSessionAttribute(ActionRequest request,
831: PortletSession ses, String paramName, int sessionScope) {
832: String[] paramValues = request.getParameterValues(paramName);
833: if (paramValues != null
834: && (paramValues.length > 1 || !""
835: .equals(paramValues[0]))) {
836: ses.setAttribute(paramName, paramValues);
837: }
838: }
839:
840: private void setPortletContextAttribute(ActionRequest request,
841: PortletContext ses, String paramName) {
842: String[] paramValues = request.getParameterValues(paramName);
843: if (paramValues != null
844: && (paramValues.length > 1 || !""
845: .equals(paramValues[0]))) {
846: ses.setAttribute(paramName, paramValues);
847: }
848: }
849:
850: private void setPortletContextScopeAttribute(ActionRequest request,
851: ActionResponse response, Form form, String paramStr) {
852: PortletContext context = request.getPortletSession()
853: .getPortletContext();
854: if (StringUtil.isNotNullOrEmpty(paramStr)) {
855: String[] paramsArray = StringUtil.split(paramStr, ",");
856: for (int i = 0; i < paramsArray.length; i++) {
857: String paramName = paramsArray[i];
858: setPortletContextAttribute(request, context, paramName);
859: }
860: } else {
861: if (form == null) {
862: Enumeration params = request.getParameterNames();
863: while (params.hasMoreElements()) {
864: String paramName = (String) params.nextElement();
865: setPortletContextAttribute(request, context,
866: paramName);
867: }
868: } else {
869: List fieldList = form.getFieldList();
870: for (int i = 0; i < fieldList.size(); i++) {
871: FormField field = (FormField) fieldList.get(i);
872: String paramName = field.getName();
873: setPortletContextAttribute(request, context,
874: paramName);
875: }
876: }
877: }
878: }
879:
880: private String getRenderContentType(RenderRequest request) {
881: String contentType = MimeTypes.HTML;
882: String acceptHeader = request.getProperty("accept");
883:
884: if (acceptHeader != null) {
885: if (acceptHeader.indexOf(MimeTypes.XHTML_MP) != -1) {
886: contentType = MimeTypes.XHTML_MP;
887: } else if (acceptHeader.indexOf(MimeTypes.WML) != -1) {
888: contentType = MimeTypes.WML;
889: }
890: }
891:
892: return contentType;
893:
894: }
895:
896: private void processRedirect(ActionRequest request,
897: ActionResponse response, String redirect)
898: throws IOException {
899: if (redirect.indexOf("$") < 0) {
900: response.sendRedirect(redirect);
901: return;
902: }
903:
904: Iterator iter = request.getParameterMap().entrySet().iterator();
905: while (iter.hasNext()) {
906: Map.Entry entry = (Map.Entry) iter.next();
907: String paramName = (String) entry.getKey();
908: String[] paramValues = (String[]) entry.getValue();
909: if (redirect.indexOf("$" + paramName) > 0) {
910: if (paramValues != null && paramValues.length > 0) {
911: StringBuffer sb = new StringBuffer();
912: for (int i = 0; i < paramValues.length; i++) {
913: sb.append(paramName);
914: sb.append("=");
915: sb.append(URLEncoder.encode(paramValues[i],
916: "UTF-8"));
917: }
918: redirect = redirect.replaceAll("\\$" + paramName,
919: sb.toString());
920: }
921: }
922: }
923: response.sendRedirect(redirect);
924: }
925:
926: @SuppressWarnings("unchecked")
927: private String getLocalizedPath(String path, Locale locale) {
928: String localizedPath = (String) cpLocalizedPaths.get(path + ":"
929: + locale);
930: if (localizedPath == null) {
931: localizedPath = CommonUtil.getLocalizedPath(path, locale,
932: cpContext);
933: cpLocalizedPaths.put(path + ":" + locale, localizedPath);
934: }
935: return localizedPath;
936: }
937:
938: }
|