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 (!path.startsWith(templatePath) ||
286                            path.contains(StringPool.DOUBLE_PERIOD) ||
287                            !PortalUtil.isValidResourceId(path)) {
288    
289                            throw new PortletException(
290                                    "Path " + path + " is not accessible by this portlet");
291                    }
292            }
293    
294            @Override
295            protected void doDispatch(
296                            RenderRequest renderRequest, RenderResponse renderResponse)
297                    throws IOException, PortletException {
298    
299                    String path = getPath(renderRequest);
300    
301                    if (path != null) {
302                            if (!isProcessRenderRequest(renderRequest)) {
303                                    renderRequest.setAttribute(
304                                            WebKeys.PORTLET_DECORATE, Boolean.FALSE);
305    
306                                    return;
307                            }
308    
309                            WindowState windowState = renderRequest.getWindowState();
310    
311                            if (windowState.equals(WindowState.MINIMIZED)) {
312                                    return;
313                            }
314    
315                            include(path, renderRequest, renderResponse);
316                    }
317                    else {
318                            super.doDispatch(renderRequest, renderResponse);
319                    }
320            }
321    
322            protected String getPath(PortletRequest portletRequest) {
323                    String mvcPath = portletRequest.getParameter("mvcPath");
324    
325                    // Check deprecated parameter
326    
327                    if (mvcPath == null) {
328                            mvcPath = portletRequest.getParameter("jspPage");
329                    }
330    
331                    return mvcPath;
332            }
333    
334            protected void include(
335                            String path, ActionRequest actionRequest,
336                            ActionResponse actionResponse)
337                    throws IOException, PortletException {
338    
339                    include(
340                            path, actionRequest, actionResponse, PortletRequest.ACTION_PHASE);
341            }
342    
343            protected void include(
344                            String path, EventRequest eventRequest, EventResponse eventResponse)
345                    throws IOException, PortletException {
346    
347                    include(path, eventRequest, eventResponse, PortletRequest.EVENT_PHASE);
348            }
349    
350            protected void include(
351                            String path, PortletRequest portletRequest,
352                            PortletResponse portletResponse, String lifecycle)
353                    throws IOException, PortletException {
354    
355                    PortletContext portletContext = getPortletContext();
356    
357                    PortletRequestDispatcher portletRequestDispatcher =
358                            portletContext.getRequestDispatcher(path);
359    
360                    if (portletRequestDispatcher == null) {
361                            _log.error(path + " is not a valid include");
362                    }
363                    else {
364                            checkPath(path);
365    
366                            portletRequestDispatcher.include(portletRequest, portletResponse);
367                    }
368    
369                    if (clearRequestParameters) {
370                            if (lifecycle.equals(PortletRequest.RENDER_PHASE)) {
371                                    portletResponse.setProperty(
372                                            "clear-request-parameters", Boolean.TRUE.toString());
373                            }
374                    }
375            }
376    
377            protected void include(
378                            String path, RenderRequest renderRequest,
379                            RenderResponse renderResponse)
380                    throws IOException, PortletException {
381    
382                    include(
383                            path, renderRequest, renderResponse, PortletRequest.RENDER_PHASE);
384            }
385    
386            protected void include(
387                            String path, ResourceRequest resourceRequest,
388                            ResourceResponse resourceResponse)
389                    throws IOException, PortletException {
390    
391                    include(
392                            path, resourceRequest, resourceResponse,
393                            PortletRequest.RESOURCE_PHASE);
394            }
395    
396            protected String aboutTemplate;
397            protected boolean clearRequestParameters;
398            protected String configTemplate;
399            protected boolean copyRequestParameters;
400            protected String editDefaultsTemplate;
401            protected String editGuestTemplate;
402            protected String editTemplate;
403            protected String helpTemplate;
404            protected String previewTemplate;
405            protected String printTemplate;
406            protected String templatePath;
407            protected String viewTemplate;
408    
409            private String _getInitParameter(String name) {
410                    String value = getInitParameter(name);
411    
412                    if (value != null) {
413                            return value;
414                    }
415    
416                    // Check deprecated parameter
417    
418                    if (name.equals("template-path")) {
419                            return getInitParameter("jsp-path");
420                    }
421                    else if (name.endsWith("-template")) {
422                            name = name.substring(0, name.length() - 9) + "-jsp";
423    
424                            return getInitParameter(name);
425                    }
426    
427                    return null;
428            }
429    
430            private static Log _log = LogFactoryUtil.getLog(MVCPortlet.class);
431    
432            private ActionCommandCache _actionCommandCache;
433    
434    }