001: /**
002: * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
003: *
004: * Permission is hereby granted, free of charge, to any person obtaining a copy
005: * of this software and associated documentation files (the "Software"), to deal
006: * in the Software without restriction, including without limitation the rights
007: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
008: * copies of the Software, and to permit persons to whom the Software is
009: * furnished to do so, subject to the following conditions:
010: *
011: * The above copyright notice and this permission notice shall be included in
012: * all copies or substantial portions of the Software.
013: *
014: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
017: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
019: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
020: * SOFTWARE.
021: */package com.liferay.portal.struts;
022:
023: import com.liferay.portal.kernel.portlet.LiferayPortletURL;
024: import com.liferay.portal.kernel.security.permission.ActionKeys;
025: import com.liferay.portal.kernel.security.permission.PermissionChecker;
026: import com.liferay.portal.kernel.util.JavaConstants;
027: import com.liferay.portal.kernel.util.StringPool;
028: import com.liferay.portal.kernel.util.Validator;
029: import com.liferay.portal.model.Layout;
030: import com.liferay.portal.model.Portlet;
031: import com.liferay.portal.model.User;
032: import com.liferay.portal.security.auth.PrincipalException;
033: import com.liferay.portal.service.PortletLocalServiceUtil;
034: import com.liferay.portal.service.permission.PortletPermissionUtil;
035: import com.liferay.portal.theme.ThemeDisplay;
036: import com.liferay.portal.util.PortalUtil;
037: import com.liferay.portal.util.PropsValues;
038: import com.liferay.portal.util.WebKeys;
039: import com.liferay.portlet.ActionResponseImpl;
040: import com.liferay.portlet.PortletConfigImpl;
041: import com.liferay.portlet.PortletRequestDispatcherImpl;
042:
043: import java.io.IOException;
044:
045: import java.lang.reflect.Constructor;
046:
047: import javax.portlet.ActionRequest;
048: import javax.portlet.ActionResponse;
049: import javax.portlet.PortletException;
050: import javax.portlet.RenderRequest;
051: import javax.portlet.RenderResponse;
052:
053: import javax.servlet.ServletException;
054: import javax.servlet.http.HttpServletRequest;
055: import javax.servlet.http.HttpServletResponse;
056:
057: import org.apache.commons.logging.Log;
058: import org.apache.commons.logging.LogFactory;
059: import org.apache.struts.Globals;
060: import org.apache.struts.action.Action;
061: import org.apache.struts.action.ActionErrors;
062: import org.apache.struts.action.ActionForm;
063: import org.apache.struts.action.ActionForward;
064: import org.apache.struts.action.ActionMapping;
065: import org.apache.struts.action.ActionServlet;
066: import org.apache.struts.config.ForwardConfig;
067: import org.apache.struts.config.ModuleConfig;
068: import org.apache.struts.tiles.TilesRequestProcessor;
069:
070: /**
071: * <a href="PortletRequestProcessor.java.html"><b><i>View Source</i></b></a>
072: *
073: * @author Brian Wing Shun Chan
074: *
075: */
076: public class PortletRequestProcessor extends TilesRequestProcessor {
077:
078: public static PortletRequestProcessor getInstance(
079: ActionServlet servlet, ModuleConfig config)
080: throws ServletException {
081:
082: try {
083: String className = PropsValues.STRUTS_PORTLET_REQUEST_PROCESSOR;
084:
085: Class clazz = Class.forName(className);
086:
087: Constructor constructor = clazz.getConstructor(new Class[] {
088: ActionServlet.class, ModuleConfig.class });
089:
090: PortletRequestProcessor portletReqProcessor = (PortletRequestProcessor) constructor
091: .newInstance(new Object[] { servlet, config });
092:
093: return portletReqProcessor;
094: } catch (Exception e) {
095: _log.error(e);
096:
097: return new PortletRequestProcessor(servlet, config);
098: }
099: }
100:
101: public PortletRequestProcessor(ActionServlet servlet,
102: ModuleConfig config) throws ServletException {
103:
104: init(servlet, config);
105: }
106:
107: public void process(RenderRequest req, RenderResponse res)
108: throws IOException, ServletException {
109:
110: HttpServletRequest httpReq = PortalUtil
111: .getHttpServletRequest(req);
112: HttpServletResponse httpRes = PortalUtil
113: .getHttpServletResponse(res);
114:
115: process(httpReq, httpRes);
116: }
117:
118: public void process(ActionRequest req, ActionResponse res,
119: String path) throws IOException, ServletException {
120:
121: ActionResponseImpl resImpl = (ActionResponseImpl) res;
122:
123: HttpServletRequest httpReq = PortalUtil
124: .getHttpServletRequest(req);
125: HttpServletResponse httpRes = PortalUtil
126: .getHttpServletResponse(res);
127:
128: ActionMapping mapping = processMapping(httpReq, httpRes, path);
129:
130: if (mapping == null) {
131: return;
132: }
133:
134: if (!processRoles(httpReq, httpRes, mapping, true)) {
135: return;
136: }
137:
138: ActionForm form = processActionForm(httpReq, httpRes, mapping);
139:
140: processPopulate(httpReq, httpRes, form, mapping);
141:
142: if (!processValidateAction(httpReq, httpRes, form, mapping)) {
143: return;
144: }
145:
146: PortletAction action = (PortletAction) processActionCreate(
147: httpReq, httpRes, mapping);
148:
149: if (action == null) {
150: return;
151: }
152:
153: PortletConfigImpl portletConfig = (PortletConfigImpl) req
154: .getAttribute(JavaConstants.JAVAX_PORTLET_CONFIG);
155:
156: try {
157: if (action.isCheckMethodOnProcessAction()) {
158: if (!PortalUtil.isMethodPost(req)) {
159: String currentURL = PortalUtil.getCurrentURL(req);
160:
161: if (_log.isWarnEnabled()) {
162: _log
163: .warn("This URL can only be invoked using POST: "
164: + currentURL);
165: }
166:
167: throw new PrincipalException(currentURL);
168: }
169: }
170:
171: action
172: .processAction(mapping, form, portletConfig, req,
173: res);
174: } catch (Exception e) {
175: String exceptionId = WebKeys.PORTLET_STRUTS_EXCEPTION
176: + StringPool.PERIOD + portletConfig.getPortletId();
177:
178: req.setAttribute(exceptionId, e);
179: }
180:
181: String forward = (String) req.getAttribute(PortletAction
182: .getForwardKey(req));
183:
184: if (forward != null) {
185: String queryString = StringPool.BLANK;
186:
187: int pos = forward.indexOf("?");
188:
189: if (pos != -1) {
190: queryString = forward.substring(pos + 1, forward
191: .length());
192: forward = forward.substring(0, pos);
193: }
194:
195: ActionForward actionForward = mapping.findForward(forward);
196:
197: if ((actionForward != null)
198: && (actionForward.getRedirect())) {
199: String forwardPath = actionForward.getPath();
200:
201: if (forwardPath.startsWith("/")) {
202: LiferayPortletURL forwardURL = (LiferayPortletURL) resImpl
203: .createRenderURL();
204:
205: forwardURL.setParameter("struts_action",
206: forwardPath);
207:
208: StrutsURLEncoder.setParameters(forwardURL,
209: queryString);
210:
211: forwardPath = forwardURL.toString();
212: }
213:
214: res.sendRedirect(forwardPath);
215: }
216: }
217: }
218:
219: protected ActionForm processActionForm(HttpServletRequest req,
220: HttpServletResponse res, ActionMapping mapping) {
221:
222: ActionForm form = super .processActionForm(req, res, mapping);
223:
224: if (form instanceof InitializableActionForm) {
225: InitializableActionForm initForm = (InitializableActionForm) form;
226:
227: initForm.init(req, res, mapping);
228: }
229:
230: return form;
231: }
232:
233: protected ActionForward processActionPerform(
234: HttpServletRequest req, HttpServletResponse res,
235: Action action, ActionForm form, ActionMapping mapping)
236: throws IOException, ServletException {
237:
238: PortletConfigImpl portletConfig = (PortletConfigImpl) req
239: .getAttribute(JavaConstants.JAVAX_PORTLET_CONFIG);
240:
241: String exceptionId = WebKeys.PORTLET_STRUTS_EXCEPTION
242: + StringPool.PERIOD + portletConfig.getPortletId();
243:
244: Exception e = (Exception) req.getAttribute(exceptionId);
245:
246: if (e != null) {
247: return processException(req, res, e, form, mapping);
248: } else {
249: return super .processActionPerform(req, res, action, form,
250: mapping);
251: }
252: }
253:
254: protected void processForwardConfig(HttpServletRequest req,
255: HttpServletResponse res, ForwardConfig forward)
256: throws IOException, ServletException {
257:
258: if (forward == null) {
259: _log.error("Forward does not exist");
260: } else {
261:
262: // Don't render a null path. This is useful if you're sending a file
263: // in an exclusive window state.
264:
265: if (forward.getPath().equals(ActionConstants.COMMON_NULL)) {
266: return;
267: }
268: }
269:
270: super .processForwardConfig(req, res, forward);
271: }
272:
273: public ActionMapping processMapping(HttpServletRequest req,
274: HttpServletResponse res, String path) throws IOException {
275:
276: if (path == null) {
277: return null;
278: }
279:
280: return super .processMapping(req, res, path);
281: }
282:
283: protected boolean processRoles(HttpServletRequest req,
284: HttpServletResponse res, ActionMapping mapping)
285: throws IOException, ServletException {
286:
287: return processRoles(req, res, mapping, false);
288: }
289:
290: protected boolean processRoles(HttpServletRequest req,
291: HttpServletResponse res, ActionMapping mapping,
292: boolean action) throws IOException, ServletException {
293:
294: User user = null;
295:
296: try {
297: user = PortalUtil.getUser(req);
298: } catch (Exception e) {
299: }
300:
301: if (user == null) {
302: return true;
303: }
304:
305: String path = mapping.getPath();
306:
307: try {
308: PortletConfigImpl portletConfig = (PortletConfigImpl) req
309: .getAttribute(JavaConstants.JAVAX_PORTLET_CONFIG);
310:
311: Portlet portlet = PortletLocalServiceUtil.getPortletById(
312: user.getCompanyId(), portletConfig.getPortletId());
313:
314: if (portlet == null) {
315: return false;
316: }
317:
318: String strutsPath = path.substring(1, path
319: .lastIndexOf(StringPool.SLASH));
320:
321: if (!strutsPath.equals(portlet.getStrutsPath())) {
322: if (_log.isWarnEnabled()) {
323: _log
324: .warn("The struts path "
325: + strutsPath
326: + " does not belong "
327: + "to portlet "
328: + portlet.getPortletId()
329: + ". "
330: + "Check the definition in liferay-portlet.xml");
331: }
332:
333: throw new PrincipalException();
334: } else if (portlet.isActive()) {
335: ThemeDisplay themeDisplay = (ThemeDisplay) req
336: .getAttribute(WebKeys.THEME_DISPLAY);
337:
338: Layout layout = themeDisplay.getLayout();
339: PermissionChecker permissionChecker = themeDisplay
340: .getPermissionChecker();
341:
342: if (!PortletPermissionUtil.contains(permissionChecker,
343: layout.getPlid(), portlet, ActionKeys.VIEW)) {
344:
345: throw new PrincipalException();
346: }
347: } else if (!portlet.isActive()) {
348: ForwardConfig forwardConfig = mapping
349: .findForward(_PATH_PORTAL_PORTLET_INACTIVE);
350:
351: if (!action) {
352: processForwardConfig(req, res, forwardConfig);
353: }
354:
355: return false;
356: }
357: } catch (Exception e) {
358: if (_log.isWarnEnabled()) {
359: _log.warn(e.getMessage());
360: }
361:
362: ForwardConfig forwardConfig = mapping
363: .findForward(_PATH_PORTAL_PORTLET_ACCESS_DENIED);
364:
365: if (!action) {
366: processForwardConfig(req, res, forwardConfig);
367: }
368:
369: return false;
370: }
371:
372: return true;
373: }
374:
375: protected boolean processValidateAction(HttpServletRequest req,
376: HttpServletResponse res, ActionForm form,
377: ActionMapping mapping) throws IOException, ServletException {
378:
379: if (form == null) {
380: return true;
381: }
382:
383: if (req.getAttribute(Globals.CANCEL_KEY) != null) {
384: return true;
385: }
386:
387: if (!mapping.getValidate()) {
388: return true;
389: }
390:
391: ActionErrors errors = form.validate(mapping, req);
392:
393: if ((errors == null) || errors.isEmpty()) {
394: return true;
395: }
396:
397: if (form.getMultipartRequestHandler() != null) {
398: form.getMultipartRequestHandler().rollback();
399: }
400:
401: String input = mapping.getInput();
402:
403: if (input == null) {
404: _log
405: .error("Validation failed but no input form is available");
406:
407: return false;
408: }
409:
410: req.setAttribute(Globals.ERROR_KEY, errors);
411:
412: // Struts normally calls internalModuleRelativeForward which breaks
413: // if called inside processAction
414:
415: req.setAttribute(PortletAction.getForwardKey(req), input);
416:
417: return false;
418: }
419:
420: protected void doForward(String uri, HttpServletRequest req,
421: HttpServletResponse res) throws IOException,
422: ServletException {
423:
424: doInclude(uri, req, res);
425: }
426:
427: protected void doInclude(String uri, HttpServletRequest req,
428: HttpServletResponse res) throws IOException,
429: ServletException {
430:
431: PortletConfigImpl portletConfig = (PortletConfigImpl) req
432: .getAttribute(JavaConstants.JAVAX_PORTLET_CONFIG);
433:
434: RenderRequest renderRequest = (RenderRequest) req
435: .getAttribute(JavaConstants.JAVAX_PORTLET_REQUEST);
436:
437: RenderResponse renderResponse = (RenderResponse) req
438: .getAttribute(JavaConstants.JAVAX_PORTLET_RESPONSE);
439:
440: PortletRequestDispatcherImpl prd = (PortletRequestDispatcherImpl) portletConfig
441: .getPortletContext().getRequestDispatcher(
442: StrutsUtil.TEXT_HTML_DIR + uri);
443:
444: try {
445: if (prd == null) {
446: _log.error(uri + " is not a valid include");
447: } else {
448: prd.include(renderRequest, renderResponse, true);
449: }
450: } catch (PortletException pe) {
451: Throwable cause = pe.getCause();
452:
453: if (cause instanceof ServletException) {
454: throw (ServletException) cause;
455: } else {
456: _log.error(cause, cause);
457: }
458: }
459: }
460:
461: protected HttpServletRequest processMultipart(HttpServletRequest req) {
462:
463: // Disable Struts from automatically wrapping a multipart request
464:
465: return req;
466: }
467:
468: protected String processPath(HttpServletRequest req,
469: HttpServletResponse res) throws IOException {
470:
471: String path = req.getParameter("struts_action");
472:
473: if (_log.isDebugEnabled()) {
474: _log.debug("Getting request parameter path " + path);
475: }
476:
477: if (Validator.isNull(path)) {
478: if (_log.isDebugEnabled()) {
479: _log.debug("Getting request attribute path " + path);
480: }
481:
482: path = (String) req
483: .getAttribute(WebKeys.PORTLET_STRUTS_ACTION);
484: }
485:
486: if (path == null) {
487: PortletConfigImpl portletConfig = (PortletConfigImpl) req
488: .getAttribute(JavaConstants.JAVAX_PORTLET_CONFIG);
489:
490: _log.error(portletConfig.getPortletName()
491: + " does not have any paths specified");
492: } else {
493: if (_log.isDebugEnabled()) {
494: _log.debug("Processing path " + path);
495: }
496: }
497:
498: return path;
499: }
500:
501: private static final String _PATH_PORTAL_PORTLET_ACCESS_DENIED = "/portal/portlet_access_denied";
502:
503: private static final String _PATH_PORTAL_PORTLET_INACTIVE = "/portal/portlet_inactive";
504:
505: private static Log _log = LogFactory
506: .getLog(PortletRequestProcessor.class);
507:
508: }
|