001    /**
002     * Copyright (c) 2000-2013 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 actionRequest, ActionResponse actionResponse)
247                    throws PortletException {
248    
249                    try {
250                            checkPermissions(actionRequest);
251                    }
252                    catch (Exception e) {
253                            throw new PortletException(e);
254                    }
255    
256                    if (_actionCommandCache == null) {
257                            return super.callActionMethod(actionRequest, actionResponse);
258                    }
259    
260                    String actionName = ParamUtil.getString(
261                            actionRequest, ActionRequest.ACTION_NAME);
262    
263                    if (!actionName.contains(StringPool.COMMA)) {
264                            ActionCommand actionCommand = _actionCommandCache.getActionCommand(
265                                    actionName);
266    
267                            if (actionCommand != ActionCommandCache.EMPTY) {
268                                    return actionCommand.processCommand(
269                                            actionRequest, actionResponse);
270                            }
271                    }
272                    else {
273                            List<ActionCommand> actionCommands =
274                                    _actionCommandCache.getActionCommandChain(actionName);
275    
276                            if (actionCommands.isEmpty()) {
277                                    return false;
278                            }
279    
280                            for (ActionCommand actionCommand : actionCommands) {
281                                    if (!actionCommand.processCommand(
282                                                    actionRequest, actionResponse)) {
283    
284                                            return false;
285                                    }
286                            }
287    
288                            return true;
289                    }
290    
291                    return false;
292            }
293    
294            protected void checkPath(String path) throws PortletException {
295                    if (Validator.isNotNull(path) &&
296                            (!path.startsWith(templatePath) ||
297                             !PortalUtil.isValidResourceId(path) ||
298                             !Validator.isFilePath(path, false))) {
299    
300                            throw new PortletException(
301                                    "Path " + path + " is not accessible by this portlet");
302                    }
303            }
304    
305            protected void checkPermissions(PortletRequest portletRequest)
306                    throws Exception {
307            }
308    
309            @Override
310            protected void doDispatch(
311                            RenderRequest renderRequest, RenderResponse renderResponse)
312                    throws IOException, PortletException {
313    
314                    String path = getPath(renderRequest);
315    
316                    if (path != null) {
317                            if (!isProcessRenderRequest(renderRequest)) {
318                                    renderRequest.setAttribute(
319                                            WebKeys.PORTLET_DECORATE, Boolean.FALSE);
320    
321                                    return;
322                            }
323    
324                            WindowState windowState = renderRequest.getWindowState();
325    
326                            if (windowState.equals(WindowState.MINIMIZED)) {
327                                    return;
328                            }
329    
330                            include(path, renderRequest, renderResponse);
331                    }
332                    else {
333                            super.doDispatch(renderRequest, renderResponse);
334                    }
335            }
336    
337            protected String getPath(PortletRequest portletRequest) {
338                    String mvcPath = portletRequest.getParameter("mvcPath");
339    
340                    // Check deprecated parameter
341    
342                    if (mvcPath == null) {
343                            mvcPath = portletRequest.getParameter("jspPage");
344                    }
345    
346                    return mvcPath;
347            }
348    
349            protected void include(
350                            String path, ActionRequest actionRequest,
351                            ActionResponse actionResponse)
352                    throws IOException, PortletException {
353    
354                    include(
355                            path, actionRequest, actionResponse, PortletRequest.ACTION_PHASE);
356            }
357    
358            protected void include(
359                            String path, EventRequest eventRequest, EventResponse eventResponse)
360                    throws IOException, PortletException {
361    
362                    include(path, eventRequest, eventResponse, PortletRequest.EVENT_PHASE);
363            }
364    
365            protected void include(
366                            String path, PortletRequest portletRequest,
367                            PortletResponse portletResponse, String lifecycle)
368                    throws IOException, PortletException {
369    
370                    PortletContext portletContext = getPortletContext();
371    
372                    PortletRequestDispatcher portletRequestDispatcher =
373                            portletContext.getRequestDispatcher(path);
374    
375                    if (portletRequestDispatcher == null) {
376                            _log.error(path + " is not a valid include");
377                    }
378                    else {
379                            checkPath(path);
380    
381                            portletRequestDispatcher.include(portletRequest, portletResponse);
382                    }
383    
384                    if (clearRequestParameters) {
385                            if (lifecycle.equals(PortletRequest.RENDER_PHASE)) {
386                                    portletResponse.setProperty(
387                                            "clear-request-parameters", Boolean.TRUE.toString());
388                            }
389                    }
390            }
391    
392            protected void include(
393                            String path, RenderRequest renderRequest,
394                            RenderResponse renderResponse)
395                    throws IOException, PortletException {
396    
397                    include(
398                            path, renderRequest, renderResponse, PortletRequest.RENDER_PHASE);
399            }
400    
401            protected void include(
402                            String path, ResourceRequest resourceRequest,
403                            ResourceResponse resourceResponse)
404                    throws IOException, PortletException {
405    
406                    include(
407                            path, resourceRequest, resourceResponse,
408                            PortletRequest.RESOURCE_PHASE);
409            }
410    
411            protected String aboutTemplate;
412            protected boolean clearRequestParameters;
413            protected String configTemplate;
414            protected boolean copyRequestParameters;
415            protected String editDefaultsTemplate;
416            protected String editGuestTemplate;
417            protected String editTemplate;
418            protected String helpTemplate;
419            protected String previewTemplate;
420            protected String printTemplate;
421            protected String templatePath;
422            protected String viewTemplate;
423    
424            private String _getInitParameter(String name) {
425                    String value = getInitParameter(name);
426    
427                    if (value != null) {
428                            return value;
429                    }
430    
431                    // Check deprecated parameter
432    
433                    if (name.equals("template-path")) {
434                            return getInitParameter("jsp-path");
435                    }
436                    else if (name.endsWith("-template")) {
437                            name = name.substring(0, name.length() - 9) + "-jsp";
438    
439                            return getInitParameter(name);
440                    }
441    
442                    return null;
443            }
444    
445            private static Log _log = LogFactoryUtil.getLog(MVCPortlet.class);
446    
447            private ActionCommandCache _actionCommandCache;
448    
449    }