001    /**
002     * Copyright (c) 2000-present 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.portal.kernel.portlet.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.servlet.SessionMessages;
021    import com.liferay.portal.kernel.util.GetterUtil;
022    import com.liferay.portal.kernel.util.ParamUtil;
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 destroy() {
057                    super.destroy();
058    
059                    _mvcActionCommandCache.close();
060            }
061    
062            @Override
063            public void doAbout(
064                            RenderRequest renderRequest, RenderResponse renderResponse)
065                    throws IOException, PortletException {
066    
067                    include(aboutTemplate, renderRequest, renderResponse);
068            }
069    
070            @Override
071            public void doConfig(
072                            RenderRequest renderRequest, RenderResponse renderResponse)
073                    throws IOException, PortletException {
074    
075                    include(configTemplate, renderRequest, renderResponse);
076            }
077    
078            @Override
079            public void doEdit(
080                            RenderRequest renderRequest, RenderResponse renderResponse)
081                    throws IOException, PortletException {
082    
083                    PortletPreferences portletPreferences = renderRequest.getPreferences();
084    
085                    if (portletPreferences == null) {
086                            super.doEdit(renderRequest, renderResponse);
087                    }
088                    else {
089                            include(editTemplate, renderRequest, renderResponse);
090                    }
091            }
092    
093            @Override
094            public void doEditDefaults(
095                            RenderRequest renderRequest, RenderResponse renderResponse)
096                    throws IOException, PortletException {
097    
098                    PortletPreferences portletPreferences = renderRequest.getPreferences();
099    
100                    if (portletPreferences == null) {
101                            super.doEdit(renderRequest, renderResponse);
102                    }
103                    else {
104                            include(editDefaultsTemplate, renderRequest, renderResponse);
105                    }
106            }
107    
108            @Override
109            public void doEditGuest(
110                            RenderRequest renderRequest, RenderResponse renderResponse)
111                    throws IOException, PortletException {
112    
113                    PortletPreferences portletPreferences = renderRequest.getPreferences();
114    
115                    if (portletPreferences == null) {
116                            super.doEdit(renderRequest, renderResponse);
117                    }
118                    else {
119                            include(editGuestTemplate, renderRequest, renderResponse);
120                    }
121            }
122    
123            @Override
124            public void doHelp(
125                            RenderRequest renderRequest, RenderResponse renderResponse)
126                    throws IOException, PortletException {
127    
128                    include(helpTemplate, renderRequest, renderResponse);
129            }
130    
131            @Override
132            public void doPreview(
133                            RenderRequest renderRequest, RenderResponse renderResponse)
134                    throws IOException, PortletException {
135    
136                    include(previewTemplate, renderRequest, renderResponse);
137            }
138    
139            @Override
140            public void doPrint(
141                            RenderRequest renderRequest, RenderResponse renderResponse)
142                    throws IOException, PortletException {
143    
144                    include(printTemplate, renderRequest, renderResponse);
145            }
146    
147            @Override
148            public void doView(
149                            RenderRequest renderRequest, RenderResponse renderResponse)
150                    throws IOException, PortletException {
151    
152                    include(viewTemplate, renderRequest, renderResponse);
153            }
154    
155            @Override
156            public void init() throws PortletException {
157                    super.init();
158    
159                    templatePath = _getInitParameter("template-path");
160    
161                    if (Validator.isNull(templatePath)) {
162                            templatePath = StringPool.SLASH;
163                    }
164                    else if (templatePath.contains(StringPool.BACK_SLASH) ||
165                                     templatePath.contains(StringPool.DOUBLE_SLASH) ||
166                                     templatePath.contains(StringPool.PERIOD) ||
167                                     templatePath.contains(StringPool.SPACE)) {
168    
169                            throw new PortletException(
170                                    "template-path " + templatePath + " has invalid characters");
171                    }
172                    else if (!templatePath.startsWith(StringPool.SLASH) ||
173                                     !templatePath.endsWith(StringPool.SLASH)) {
174    
175                            throw new PortletException(
176                                    "template-path " + templatePath +
177                                            " must start and end with a /");
178                    }
179    
180                    aboutTemplate = _getInitParameter("about-template");
181                    configTemplate = _getInitParameter("config-template");
182                    editTemplate = _getInitParameter("edit-template");
183                    editDefaultsTemplate = _getInitParameter("edit-defaults-template");
184                    editGuestTemplate = _getInitParameter("edit-guest-template");
185                    helpTemplate = _getInitParameter("help-template");
186                    previewTemplate = _getInitParameter("preview-template");
187                    printTemplate = _getInitParameter("print-template");
188                    viewTemplate = _getInitParameter("view-template");
189    
190                    clearRequestParameters = GetterUtil.getBoolean(
191                            getInitParameter("clear-request-parameters"));
192                    copyRequestParameters = GetterUtil.getBoolean(
193                            getInitParameter("copy-request-parameters"), true);
194    
195                    String packagePrefix = getInitParameter("action.package.prefix");
196    
197                    _mvcActionCommandCache = new MVCActionCommandCache(
198                            packagePrefix, getPortletName());
199            }
200    
201            public void invokeTaglibDiscussion(
202                            ActionRequest actionRequest, ActionResponse actionResponse)
203                    throws Exception {
204    
205                    PortletConfig portletConfig = getPortletConfig();
206    
207                    PortalUtil.invokeTaglibDiscussion(
208                            portletConfig, actionRequest, actionResponse);
209            }
210    
211            public void invokeTaglibDiscussionPagination(
212                            ResourceRequest resourceRequest, ResourceResponse resourceResponse)
213                    throws IOException, PortletException {
214    
215                    PortletConfig portletConfig = getPortletConfig();
216    
217                    PortalUtil.invokeTaglibDiscussionPagination(
218                            portletConfig, resourceRequest, resourceResponse);
219            }
220    
221            @Override
222            public void processAction(
223                            ActionRequest actionRequest, ActionResponse actionResponse)
224                    throws IOException, PortletException {
225    
226                    super.processAction(actionRequest, actionResponse);
227    
228                    if (copyRequestParameters) {
229                            PortalUtil.copyRequestParameters(actionRequest, actionResponse);
230                    }
231            }
232    
233            @Override
234            public void serveResource(
235                            ResourceRequest resourceRequest, ResourceResponse resourceResponse)
236                    throws IOException, PortletException {
237    
238                    String path = getPath(resourceRequest);
239    
240                    if (path != null) {
241                            include(
242                                    path, resourceRequest, resourceResponse,
243                                    PortletRequest.RESOURCE_PHASE);
244                    }
245    
246                    boolean invokeTaglibDiscussion = GetterUtil.getBoolean(
247                            resourceRequest.getParameter("invokeTaglibDiscussion"));
248    
249                    if (invokeTaglibDiscussion) {
250                            invokeTaglibDiscussionPagination(resourceRequest, resourceResponse);
251                    }
252                    else {
253                            super.serveResource(resourceRequest, resourceResponse);
254                    }
255            }
256    
257            @Override
258            protected boolean callActionMethod(
259                            ActionRequest actionRequest, ActionResponse actionResponse)
260                    throws PortletException {
261    
262                    try {
263                            checkPermissions(actionRequest);
264                    }
265                    catch (Exception e) {
266                            throw new PortletException(e);
267                    }
268    
269                    String actionName = ParamUtil.getString(
270                            actionRequest, ActionRequest.ACTION_NAME);
271    
272                    if (!actionName.contains(StringPool.COMMA)) {
273                            MVCActionCommand mvcActionCommand =
274                                    _mvcActionCommandCache.getMVCActionCommand(actionName);
275    
276                            if (mvcActionCommand != MVCActionCommandCache.EMPTY) {
277                                    return mvcActionCommand.processAction(
278                                            actionRequest, actionResponse);
279                            }
280                    }
281                    else {
282                            List<MVCActionCommand> mvcActionCommands =
283                                    _mvcActionCommandCache.getMVCActionCommandChain(actionName);
284    
285                            if (!mvcActionCommands.isEmpty()) {
286                                    for (MVCActionCommand mvcActionCommand : mvcActionCommands) {
287                                            if (!mvcActionCommand.processAction(
288                                                            actionRequest, actionResponse)) {
289    
290                                                    return false;
291                                            }
292                                    }
293    
294                                    return true;
295                            }
296                    }
297    
298                    return super.callActionMethod(actionRequest, actionResponse);
299            }
300    
301            @Override
302            protected boolean callResourceMethod(
303                            ResourceRequest resourceRequest, ResourceResponse resourceResponse)
304                    throws PortletException {
305    
306                    try {
307                            checkPermissions(resourceRequest);
308                    }
309                    catch (Exception e) {
310                            throw new PortletException(e);
311                    }
312    
313                    String actionName = ParamUtil.getString(
314                            resourceRequest, ActionRequest.ACTION_NAME);
315    
316                    if (!actionName.contains(StringPool.COMMA)) {
317                            MVCActionCommand mvcActionCommand =
318                                    _mvcActionCommandCache.getMVCActionCommand(actionName);
319    
320                            if (mvcActionCommand != MVCActionCommandCache.EMPTY) {
321                                    return mvcActionCommand.processAction(
322                                            resourceRequest, resourceResponse);
323                            }
324                    }
325                    else {
326                            List<MVCActionCommand> mvcActionCommands =
327                                    _mvcActionCommandCache.getMVCActionCommandChain(actionName);
328    
329                            if (!mvcActionCommands.isEmpty()) {
330                                    for (MVCActionCommand mvcActionCommand : mvcActionCommands) {
331                                            if (!mvcActionCommand.processAction(
332                                                            resourceRequest, resourceResponse)) {
333    
334                                                    return false;
335                                            }
336                                    }
337    
338                                    return true;
339                            }
340                    }
341    
342                    return super.callResourceMethod(resourceRequest, resourceResponse);
343            }
344    
345            protected void checkPath(String path) throws PortletException {
346                    if (Validator.isNotNull(path) &&
347                            (!path.startsWith(templatePath) ||
348                             !PortalUtil.isValidResourceId(path) ||
349                             !Validator.isFilePath(path, false))) {
350    
351                            throw new PortletException(
352                                    "Path " + path + " is not accessible by this portlet");
353                    }
354            }
355    
356            protected void checkPermissions(PortletRequest portletRequest)
357                    throws Exception {
358            }
359    
360            @Override
361            protected void doDispatch(
362                            RenderRequest renderRequest, RenderResponse renderResponse)
363                    throws IOException, PortletException {
364    
365                    String path = getPath(renderRequest);
366    
367                    if (path != null) {
368                            if (!isProcessRenderRequest(renderRequest)) {
369                                    renderRequest.setAttribute(
370                                            WebKeys.PORTLET_DECORATE, Boolean.FALSE);
371    
372                                    return;
373                            }
374    
375                            WindowState windowState = renderRequest.getWindowState();
376    
377                            if (windowState.equals(WindowState.MINIMIZED)) {
378                                    return;
379                            }
380    
381                            include(path, renderRequest, renderResponse);
382                    }
383                    else {
384                            super.doDispatch(renderRequest, renderResponse);
385                    }
386            }
387    
388            protected String getPath(PortletRequest portletRequest) {
389                    String mvcPath = portletRequest.getParameter("mvcPath");
390    
391                    // Check deprecated parameter
392    
393                    if (mvcPath == null) {
394                            mvcPath = portletRequest.getParameter("jspPage");
395                    }
396    
397                    return mvcPath;
398            }
399    
400            protected void hideDefaultErrorMessage(PortletRequest portletRequest) {
401                    SessionMessages.add(
402                            portletRequest,
403                            PortalUtil.getPortletId(portletRequest) +
404                                    SessionMessages.KEY_SUFFIX_HIDE_DEFAULT_ERROR_MESSAGE);
405            }
406    
407            protected void hideDefaultSuccessMessage(PortletRequest portletRequest) {
408                    SessionMessages.add(
409                            portletRequest,
410                            PortalUtil.getPortletId(portletRequest) +
411                                    SessionMessages.KEY_SUFFIX_HIDE_DEFAULT_SUCCESS_MESSAGE);
412            }
413    
414            protected void include(
415                            String path, ActionRequest actionRequest,
416                            ActionResponse actionResponse)
417                    throws IOException, PortletException {
418    
419                    include(
420                            path, actionRequest, actionResponse, PortletRequest.ACTION_PHASE);
421            }
422    
423            protected void include(
424                            String path, EventRequest eventRequest, EventResponse eventResponse)
425                    throws IOException, PortletException {
426    
427                    include(path, eventRequest, eventResponse, PortletRequest.EVENT_PHASE);
428            }
429    
430            protected void include(
431                            String path, PortletRequest portletRequest,
432                            PortletResponse portletResponse, String lifecycle)
433                    throws IOException, PortletException {
434    
435                    PortletContext portletContext = getPortletContext();
436    
437                    PortletRequestDispatcher portletRequestDispatcher =
438                            portletContext.getRequestDispatcher(path);
439    
440                    if (portletRequestDispatcher == null) {
441                            _log.error(path + " is not a valid include");
442                    }
443                    else {
444                            checkPath(path);
445    
446                            portletRequestDispatcher.include(portletRequest, portletResponse);
447                    }
448    
449                    if (clearRequestParameters) {
450                            if (lifecycle.equals(PortletRequest.RENDER_PHASE)) {
451                                    portletResponse.setProperty(
452                                            "clear-request-parameters", Boolean.TRUE.toString());
453                            }
454                    }
455            }
456    
457            protected void include(
458                            String path, RenderRequest renderRequest,
459                            RenderResponse renderResponse)
460                    throws IOException, PortletException {
461    
462                    include(
463                            path, renderRequest, renderResponse, PortletRequest.RENDER_PHASE);
464            }
465    
466            protected void include(
467                            String path, ResourceRequest resourceRequest,
468                            ResourceResponse resourceResponse)
469                    throws IOException, PortletException {
470    
471                    include(
472                            path, resourceRequest, resourceResponse,
473                            PortletRequest.RESOURCE_PHASE);
474            }
475    
476            protected String aboutTemplate;
477            protected boolean clearRequestParameters;
478            protected String configTemplate;
479            protected boolean copyRequestParameters;
480            protected String editDefaultsTemplate;
481            protected String editGuestTemplate;
482            protected String editTemplate;
483            protected String helpTemplate;
484            protected String previewTemplate;
485            protected String printTemplate;
486            protected String templatePath;
487            protected String viewTemplate;
488    
489            private String _getInitParameter(String name) {
490                    String value = getInitParameter(name);
491    
492                    if (value != null) {
493                            return value;
494                    }
495    
496                    // Check deprecated parameter
497    
498                    if (name.equals("template-path")) {
499                            return getInitParameter("jsp-path");
500                    }
501                    else if (name.endsWith("-template")) {
502                            name = name.substring(0, name.length() - 9) + "-jsp";
503    
504                            return getInitParameter(name);
505                    }
506    
507                    return null;
508            }
509    
510            private static final Log _log = LogFactoryUtil.getLog(MVCPortlet.class);
511    
512            private MVCActionCommandCache _mvcActionCommandCache;
513    
514    }