001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.util.bridges.mvc;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.portlet.LiferayPortlet;
020    import com.liferay.portal.kernel.util.GetterUtil;
021    import com.liferay.portal.kernel.util.ParamUtil;
022    import com.liferay.portal.kernel.util.PortalClassInvoker;
023    import com.liferay.portal.kernel.util.StringPool;
024    import com.liferay.portal.kernel.util.Validator;
025    import com.liferay.portal.kernel.util.WebKeys;
026    import com.liferay.portal.util.PortalUtil;
027    
028    import java.io.IOException;
029    
030    import java.util.List;
031    
032    import javax.portlet.ActionRequest;
033    import javax.portlet.ActionResponse;
034    import javax.portlet.EventRequest;
035    import javax.portlet.EventResponse;
036    import javax.portlet.PortletConfig;
037    import javax.portlet.PortletContext;
038    import javax.portlet.PortletException;
039    import javax.portlet.PortletPreferences;
040    import javax.portlet.PortletRequest;
041    import javax.portlet.PortletRequestDispatcher;
042    import javax.portlet.PortletResponse;
043    import javax.portlet.RenderRequest;
044    import javax.portlet.RenderResponse;
045    import javax.portlet.ResourceRequest;
046    import javax.portlet.ResourceResponse;
047    import javax.portlet.WindowState;
048    
049    /**
050     * @author Brian Wing Shun Chan
051     * @author Raymond Augé
052     */
053    public class MVCPortlet extends LiferayPortlet {
054    
055            @Override
056            public void doAbout(
057                            RenderRequest renderRequest, RenderResponse renderResponse)
058                    throws IOException, PortletException {
059    
060                    include(aboutTemplate, renderRequest, renderResponse);
061            }
062    
063            @Override
064            public void doConfig(
065                            RenderRequest renderRequest, RenderResponse renderResponse)
066                    throws IOException, PortletException {
067    
068                    include(configTemplate, renderRequest, renderResponse);
069            }
070    
071            @Override
072            public void doEdit(
073                            RenderRequest renderRequest, RenderResponse renderResponse)
074                    throws IOException, PortletException {
075    
076                    PortletPreferences portletPreferences = renderRequest.getPreferences();
077    
078                    if (portletPreferences == null) {
079                            super.doEdit(renderRequest, renderResponse);
080                    }
081                    else {
082                            include(editTemplate, renderRequest, renderResponse);
083                    }
084            }
085    
086            @Override
087            public void doEditDefaults(
088                            RenderRequest renderRequest, RenderResponse renderResponse)
089                    throws IOException, PortletException {
090    
091                    PortletPreferences portletPreferences = renderRequest.getPreferences();
092    
093                    if (portletPreferences == null) {
094                            super.doEdit(renderRequest, renderResponse);
095                    }
096                    else {
097                            include(editDefaultsTemplate, renderRequest, renderResponse);
098                    }
099            }
100    
101            @Override
102            public void doEditGuest(
103                            RenderRequest renderRequest, RenderResponse renderResponse)
104                    throws IOException, PortletException {
105    
106                    PortletPreferences portletPreferences = renderRequest.getPreferences();
107    
108                    if (portletPreferences == null) {
109                            super.doEdit(renderRequest, renderResponse);
110                    }
111                    else {
112                            include(editGuestTemplate, renderRequest, renderResponse);
113                    }
114            }
115    
116            @Override
117            public void doHelp(
118                            RenderRequest renderRequest, RenderResponse renderResponse)
119                    throws IOException, PortletException {
120    
121                    include(helpTemplate, renderRequest, renderResponse);
122            }
123    
124            @Override
125            public void doPreview(
126                            RenderRequest renderRequest, RenderResponse renderResponse)
127                    throws IOException, PortletException {
128    
129                    include(previewTemplate, renderRequest, renderResponse);
130            }
131    
132            @Override
133            public void doPrint(
134                            RenderRequest renderRequest, RenderResponse renderResponse)
135                    throws IOException, PortletException {
136    
137                    include(printTemplate, renderRequest, renderResponse);
138            }
139    
140            @Override
141            public void doView(
142                            RenderRequest renderRequest, RenderResponse renderResponse)
143                    throws IOException, PortletException {
144    
145                    include(viewTemplate, renderRequest, renderResponse);
146            }
147    
148            @Override
149            public void init() throws PortletException {
150                    super.init();
151    
152                    templatePath = _getInitParameter("template-path");
153    
154                    if (Validator.isNull(templatePath)) {
155                            templatePath = StringPool.SLASH;
156                    }
157                    else if (templatePath.contains(StringPool.BACK_SLASH) ||
158                                     templatePath.contains(StringPool.DOUBLE_SLASH) ||
159                                     templatePath.contains(StringPool.PERIOD) ||
160                                     templatePath.contains(StringPool.SPACE)) {
161    
162                            throw new PortletException(
163                                    "template-path " + templatePath + " has invalid characters");
164                    }
165                    else if (!templatePath.startsWith(StringPool.SLASH) ||
166                                     !templatePath.endsWith(StringPool.SLASH)) {
167    
168                            throw new PortletException(
169                                    "template-path " + templatePath +
170                                            " must start and end with a /");
171                    }
172    
173                    aboutTemplate = _getInitParameter("about-template");
174                    configTemplate = _getInitParameter("config-template");
175                    editTemplate = _getInitParameter("edit-template");
176                    editDefaultsTemplate = _getInitParameter("edit-defaults-template");
177                    editGuestTemplate = _getInitParameter("edit-guest-template");
178                    helpTemplate = _getInitParameter("help-template");
179                    previewTemplate = _getInitParameter("preview-template");
180                    printTemplate = _getInitParameter("print-template");
181                    viewTemplate = _getInitParameter("view-template");
182    
183                    clearRequestParameters = GetterUtil.getBoolean(
184                            getInitParameter("clear-request-parameters"));
185                    copyRequestParameters = GetterUtil.getBoolean(
186                            getInitParameter("copy-request-parameters"));
187    
188                    String packagePrefix = getInitParameter(
189                            ActionCommandCache.ACTION_PACKAGE_NAME);
190    
191                    if (Validator.isNotNull(packagePrefix)) {
192                            _actionCommandCache = new ActionCommandCache(packagePrefix);
193                    }
194            }
195    
196            public void invokeTaglibDiscussion(
197                            ActionRequest actionRequest, ActionResponse actionResponse)
198                    throws Exception {
199    
200                    PortletConfig portletConfig = getPortletConfig();
201    
202                    PortalClassInvoker.invoke(
203                            true,
204                            "com.liferay.portlet.messageboards.action.EditDiscussionAction",
205                            "processAction",
206                            new String[] {
207                                    "org.apache.struts.action.ActionMapping",
208                                    "org.apache.struts.action.ActionForm",
209                                    PortletConfig.class.getName(), ActionRequest.class.getName(),
210                                    ActionResponse.class.getName()
211                            },
212                            null, null, portletConfig, actionRequest, actionResponse);
213            }
214    
215            @Override
216            public void processAction(
217                            ActionRequest actionRequest, ActionResponse actionResponse)
218                    throws IOException, PortletException {
219    
220                    super.processAction(actionRequest, actionResponse);
221    
222                    if (copyRequestParameters) {
223                            PortalUtil.copyRequestParameters(actionRequest, actionResponse);
224                    }
225            }
226    
227            @Override
228            public void serveResource(
229                            ResourceRequest resourceRequest, ResourceResponse resourceResponse)
230                    throws IOException, PortletException {
231    
232                    String path = getPath(resourceRequest);
233    
234                    if (path != null) {
235                            include(
236                                    path, resourceRequest, resourceResponse,
237                                    PortletRequest.RESOURCE_PHASE);
238                    }
239                    else {
240                            super.serveResource(resourceRequest, resourceResponse);
241                    }
242            }
243    
244            @Override
245            protected boolean callActionMethod(
246                            ActionRequest request, ActionResponse response)
247                    throws PortletException {
248    
249                    if (_actionCommandCache == null) {
250                            return super.callActionMethod(request, response);
251                    }
252    
253                    String actionName = ParamUtil.getString(
254                            request, ActionRequest.ACTION_NAME);
255    
256                    if (!actionName.contains(StringPool.COMMA)) {
257                            ActionCommand actionCommand = _actionCommandCache.getActionCommand(
258                                    actionName);
259    
260                            if (actionCommand != ActionCommandCache.EMPTY) {
261                                    return actionCommand.processCommand(request, response);
262                            }
263                    }
264                    else {
265                            List<ActionCommand> actionCommands =
266                                    _actionCommandCache.getActionCommandChain(actionName);
267    
268                            if (actionCommands.isEmpty()) {
269                                    return false;
270                            }
271    
272                            for (ActionCommand actionCommand : actionCommands) {
273                                    if (!actionCommand.processCommand(request, response)) {
274                                            return false;
275                                    }
276                            }
277    
278                            return true;
279                    }
280    
281                    return false;
282            }
283    
284            protected void checkPath(String path) throws PortletException {
285                    if (Validator.isNotNull(path) &&
286                            (!path.startsWith(templatePath) ||
287                             !PortalUtil.isValidResourceId(path) ||
288                             !Validator.isFilePath(path, false))) {
289    
290                            throw new PortletException(
291                                    "Path " + path + " is not accessible by this portlet");
292                    }
293            }
294    
295            @Override
296            protected void doDispatch(
297                            RenderRequest renderRequest, RenderResponse renderResponse)
298                    throws IOException, PortletException {
299    
300                    String path = getPath(renderRequest);
301    
302                    if (path != null) {
303                            if (!isProcessRenderRequest(renderRequest)) {
304                                    renderRequest.setAttribute(
305                                            WebKeys.PORTLET_DECORATE, Boolean.FALSE);
306    
307                                    return;
308                            }
309    
310                            WindowState windowState = renderRequest.getWindowState();
311    
312                            if (windowState.equals(WindowState.MINIMIZED)) {
313                                    return;
314                            }
315    
316                            include(path, renderRequest, renderResponse);
317                    }
318                    else {
319                            super.doDispatch(renderRequest, renderResponse);
320                    }
321            }
322    
323            protected String getPath(PortletRequest portletRequest) {
324                    String mvcPath = portletRequest.getParameter("mvcPath");
325    
326                    // Check deprecated parameter
327    
328                    if (mvcPath == null) {
329                            mvcPath = portletRequest.getParameter("jspPage");
330                    }
331    
332                    return mvcPath;
333            }
334    
335            protected void include(
336                            String path, ActionRequest actionRequest,
337                            ActionResponse actionResponse)
338                    throws IOException, PortletException {
339    
340                    include(
341                            path, actionRequest, actionResponse, PortletRequest.ACTION_PHASE);
342            }
343    
344            protected void include(
345                            String path, EventRequest eventRequest, EventResponse eventResponse)
346                    throws IOException, PortletException {
347    
348                    include(path, eventRequest, eventResponse, PortletRequest.EVENT_PHASE);
349            }
350    
351            protected void include(
352                            String path, PortletRequest portletRequest,
353                            PortletResponse portletResponse, String lifecycle)
354                    throws IOException, PortletException {
355    
356                    PortletContext portletContext = getPortletContext();
357    
358                    PortletRequestDispatcher portletRequestDispatcher =
359                            portletContext.getRequestDispatcher(path);
360    
361                    if (portletRequestDispatcher == null) {
362                            _log.error(path + " is not a valid include");
363                    }
364                    else {
365                            checkPath(path);
366    
367                            portletRequestDispatcher.include(portletRequest, portletResponse);
368                    }
369    
370                    if (clearRequestParameters) {
371                            if (lifecycle.equals(PortletRequest.RENDER_PHASE)) {
372                                    portletResponse.setProperty(
373                                            "clear-request-parameters", Boolean.TRUE.toString());
374                            }
375                    }
376            }
377    
378            protected void include(
379                            String path, RenderRequest renderRequest,
380                            RenderResponse renderResponse)
381                    throws IOException, PortletException {
382    
383                    include(
384                            path, renderRequest, renderResponse, PortletRequest.RENDER_PHASE);
385            }
386    
387            protected void include(
388                            String path, ResourceRequest resourceRequest,
389                            ResourceResponse resourceResponse)
390                    throws IOException, PortletException {
391    
392                    include(
393                            path, resourceRequest, resourceResponse,
394                            PortletRequest.RESOURCE_PHASE);
395            }
396    
397            protected String aboutTemplate;
398            protected boolean clearRequestParameters;
399            protected String configTemplate;
400            protected boolean copyRequestParameters;
401            protected String editDefaultsTemplate;
402            protected String editGuestTemplate;
403            protected String editTemplate;
404            protected String helpTemplate;
405            protected String previewTemplate;
406            protected String printTemplate;
407            protected String templatePath;
408            protected String viewTemplate;
409    
410            private String _getInitParameter(String name) {
411                    String value = getInitParameter(name);
412    
413                    if (value != null) {
414                            return value;
415                    }
416    
417                    // Check deprecated parameter
418    
419                    if (name.equals("template-path")) {
420                            return getInitParameter("jsp-path");
421                    }
422                    else if (name.endsWith("-template")) {
423                            name = name.substring(0, name.length() - 9) + "-jsp";
424    
425                            return getInitParameter(name);
426                    }
427    
428                    return null;
429            }
430    
431            private static Log _log = LogFactoryUtil.getLog(MVCPortlet.class);
432    
433            private ActionCommandCache _actionCommandCache;
434    
435    }