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;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.language.LanguageUtil;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.servlet.BrowserSnifferUtil;
022    import com.liferay.portal.kernel.servlet.ServletResponseUtil;
023    import com.liferay.portal.kernel.servlet.SessionErrors;
024    import com.liferay.portal.kernel.servlet.SessionMessages;
025    import com.liferay.portal.kernel.util.ContentTypes;
026    import com.liferay.portal.kernel.util.GetterUtil;
027    import com.liferay.portal.kernel.util.ParamUtil;
028    import com.liferay.portal.kernel.util.Validator;
029    import com.liferay.portal.kernel.util.WebKeys;
030    import com.liferay.portal.model.Portlet;
031    import com.liferay.portal.model.PortletApp;
032    import com.liferay.portal.theme.ThemeDisplay;
033    import com.liferay.portal.util.PortalUtil;
034    
035    import java.io.IOException;
036    
037    import java.lang.reflect.InvocationTargetException;
038    import java.lang.reflect.Method;
039    
040    import java.util.Map;
041    import java.util.ResourceBundle;
042    import java.util.concurrent.ConcurrentHashMap;
043    
044    import javax.portlet.ActionRequest;
045    import javax.portlet.ActionResponse;
046    import javax.portlet.GenericPortlet;
047    import javax.portlet.MimeResponse;
048    import javax.portlet.PortletException;
049    import javax.portlet.PortletMode;
050    import javax.portlet.PortletRequest;
051    import javax.portlet.RenderRequest;
052    import javax.portlet.RenderResponse;
053    import javax.portlet.ResourceRequest;
054    import javax.portlet.ResourceResponse;
055    import javax.portlet.WindowState;
056    
057    import javax.servlet.ServletContext;
058    import javax.servlet.http.HttpServletRequest;
059    import javax.servlet.http.HttpServletResponse;
060    
061    /**
062     * @author Brian Wing Shun Chan
063     */
064    public class LiferayPortlet extends GenericPortlet {
065    
066            @Override
067            public void init() throws PortletException {
068                    super.init();
069    
070                    addProcessActionSuccessMessage = GetterUtil.getBoolean(
071                            getInitParameter("add-process-action-success-action"), true);
072                    alwaysSendRedirect = GetterUtil.getBoolean(
073                            getInitParameter("always-send-redirect"));
074            }
075    
076            @Override
077            public void processAction(
078                            ActionRequest actionRequest, ActionResponse actionResponse)
079                    throws IOException, PortletException {
080    
081                    try {
082                            if (!isProcessActionRequest(actionRequest)) {
083                                    return;
084                            }
085    
086                            if (!callActionMethod(actionRequest, actionResponse)) {
087                                    return;
088                            }
089    
090                            if (!SessionErrors.isEmpty(actionRequest)) {
091                                    return;
092                            }
093    
094                            boolean emptySessionMessages = isEmptySessionMessages(
095                                    actionRequest);
096    
097                            if (emptySessionMessages) {
098                                    addSuccessMessage(actionRequest, actionResponse);
099                            }
100    
101                            if (!SessionMessages.contains(
102                                            actionRequest,
103                                            PortalUtil.getPortletId(actionRequest) +
104                                                    SessionMessages.KEY_SUFFIX_FORCE_SEND_REDIRECT)) {
105    
106                                    if (emptySessionMessages || isAlwaysSendRedirect()) {
107                                            sendRedirect(actionRequest, actionResponse);
108                                    }
109                            }
110                    }
111                    catch (PortletException pe) {
112                            Throwable cause = pe.getCause();
113    
114                            if (isSessionErrorException(cause)) {
115                                    SessionErrors.add(actionRequest, cause.getClass(), cause);
116                            }
117                            else {
118                                    throw pe;
119                            }
120                    }
121            }
122    
123            @Override
124            public void serveResource(
125                            ResourceRequest resourceRequest, ResourceResponse resourceResponse)
126                    throws IOException, PortletException {
127    
128                    if (!isProcessResourceRequest(resourceRequest)) {
129                            return;
130                    }
131    
132                    if (!callResourceMethod(resourceRequest, resourceResponse)) {
133                            return;
134                    }
135    
136                    if (!SessionErrors.isEmpty(resourceRequest)) {
137                            return;
138                    }
139    
140                    if (!SessionMessages.isEmpty(resourceRequest)) {
141                            return;
142                    }
143    
144                    super.serveResource(resourceRequest, resourceResponse);
145            }
146    
147            protected void addSuccessMessage(
148                    ActionRequest actionRequest, ActionResponse actionResponse) {
149    
150                    if (!addProcessActionSuccessMessage) {
151                            return;
152                    }
153    
154                    String successMessage = ParamUtil.getString(
155                            actionRequest, "successMessage");
156    
157                    SessionMessages.add(actionRequest, "requestProcessed", successMessage);
158            }
159    
160            protected boolean callActionMethod(
161                            ActionRequest actionRequest, ActionResponse actionResponse)
162                    throws PortletException {
163    
164                    String actionName = ParamUtil.getString(
165                            actionRequest, ActionRequest.ACTION_NAME);
166    
167                    if (Validator.isNull(actionName) ||
168                            actionName.equals("callActionMethod") ||
169                            actionName.equals("processAction")) {
170    
171                            return false;
172                    }
173    
174                    try {
175                            Method method = getActionMethod(actionName);
176    
177                            method.invoke(this, actionRequest, actionResponse);
178    
179                            return true;
180                    }
181                    catch (NoSuchMethodException nsme) {
182                            try {
183                                    super.processAction(actionRequest, actionResponse);
184    
185                                    return true;
186                            }
187                            catch (Exception e) {
188                                    throw new PortletException(e);
189                            }
190                    }
191                    catch (InvocationTargetException ite) {
192                            Throwable cause = ite.getCause();
193    
194                            if (cause != null) {
195                                    throw new PortletException(cause);
196                            }
197                            else {
198                                    throw new PortletException(ite);
199                            }
200                    }
201                    catch (Exception e) {
202                            throw new PortletException(e);
203                    }
204            }
205    
206            protected boolean callResourceMethod(
207                            ResourceRequest resourceRequest, ResourceResponse resourceResponse)
208                    throws PortletException {
209    
210                    String actionName = ParamUtil.getString(
211                            resourceRequest, ActionRequest.ACTION_NAME);
212    
213                    if (Validator.isNull(actionName) ||
214                            actionName.equals("callResourceMethod") ||
215                            actionName.equals("serveResource")) {
216    
217                            return false;
218                    }
219    
220                    try {
221                            Method method = getResourceMethod(actionName);
222    
223                            method.invoke(this, resourceRequest, resourceResponse);
224    
225                            return true;
226                    }
227                    catch (NoSuchMethodException nsme) {
228                            try {
229                                    super.serveResource(resourceRequest, resourceResponse);
230    
231                                    return true;
232                            }
233                            catch (Exception e) {
234                                    throw new PortletException(e);
235                            }
236                    }
237                    catch (InvocationTargetException ite) {
238                            Throwable cause = ite.getCause();
239    
240                            if (cause != null) {
241                                    throw new PortletException(cause);
242                            }
243                            else {
244                                    throw new PortletException(ite);
245                            }
246                    }
247                    catch (Exception e) {
248                            throw new PortletException(e);
249                    }
250            }
251    
252            @SuppressWarnings("unused")
253            protected void doAbout(
254                            RenderRequest renderRequest, RenderResponse renderResponse)
255                    throws IOException, PortletException {
256    
257                    throw new PortletException("doAbout method not implemented");
258            }
259    
260            @SuppressWarnings("unused")
261            protected void doConfig(
262                            RenderRequest renderRequest, RenderResponse renderResponse)
263                    throws IOException, PortletException {
264    
265                    throw new PortletException("doConfig method not implemented");
266            }
267    
268            @Override
269            protected void doDispatch(
270                            RenderRequest renderRequest, RenderResponse renderResponse)
271                    throws IOException, PortletException {
272    
273                    if (!isProcessRenderRequest(renderRequest)) {
274                            renderRequest.setAttribute(WebKeys.PORTLET_DECORATE, Boolean.FALSE);
275    
276                            return;
277                    }
278    
279                    WindowState windowState = renderRequest.getWindowState();
280    
281                    if (windowState.equals(WindowState.MINIMIZED)) {
282                            return;
283                    }
284    
285                    PortletMode portletMode = renderRequest.getPortletMode();
286    
287                    if (portletMode.equals(PortletMode.VIEW)) {
288                            doView(renderRequest, renderResponse);
289                    }
290                    else if (portletMode.equals(LiferayPortletMode.ABOUT)) {
291                            doAbout(renderRequest, renderResponse);
292                    }
293                    else if (portletMode.equals(LiferayPortletMode.CONFIG)) {
294                            doConfig(renderRequest, renderResponse);
295                    }
296                    else if (portletMode.equals(PortletMode.EDIT)) {
297                            doEdit(renderRequest, renderResponse);
298                    }
299                    else if (portletMode.equals(LiferayPortletMode.EDIT_DEFAULTS)) {
300                            doEditDefaults(renderRequest, renderResponse);
301                    }
302                    else if (portletMode.equals(LiferayPortletMode.EDIT_GUEST)) {
303                            doEditGuest(renderRequest, renderResponse);
304                    }
305                    else if (portletMode.equals(PortletMode.HELP)) {
306                            doHelp(renderRequest, renderResponse);
307                    }
308                    else if (portletMode.equals(LiferayPortletMode.PREVIEW)) {
309                            doPreview(renderRequest, renderResponse);
310                    }
311                    else if (portletMode.equals(LiferayPortletMode.PRINT)) {
312                            doPrint(renderRequest, renderResponse);
313                    }
314                    else {
315                            throw new PortletException(portletMode.toString());
316                    }
317            }
318    
319            @SuppressWarnings("unused")
320            protected void doEditDefaults(
321                            RenderRequest renderRequest, RenderResponse renderResponse)
322                    throws IOException, PortletException {
323    
324                    throw new PortletException("doEditDefaults method not implemented");
325            }
326    
327            @SuppressWarnings("unused")
328            protected void doEditGuest(
329                            RenderRequest renderRequest, RenderResponse renderResponse)
330                    throws IOException, PortletException {
331    
332                    throw new PortletException("doEditGuest method not implemented");
333            }
334    
335            @SuppressWarnings("unused")
336            protected void doPreview(
337                            RenderRequest renderRequest, RenderResponse renderResponse)
338                    throws IOException, PortletException {
339    
340                    throw new PortletException("doPreview method not implemented");
341            }
342    
343            @SuppressWarnings("unused")
344            protected void doPrint(
345                            RenderRequest renderRequest, RenderResponse renderResponse)
346                    throws IOException, PortletException {
347    
348                    throw new PortletException("doPrint method not implemented");
349            }
350    
351            protected Method getActionMethod(String actionName)
352                    throws NoSuchMethodException {
353    
354                    Method method = _actionMethods.get(actionName);
355    
356                    if (method != null) {
357                            return method;
358                    }
359    
360                    Class<?> clazz = getClass();
361    
362                    method = clazz.getMethod(
363                            actionName, ActionRequest.class, ActionResponse.class);
364    
365                    _actionMethods.put(actionName, method);
366    
367                    return method;
368            }
369    
370            protected String getJSONContentType(PortletRequest portletRequest) {
371                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
372                            portletRequest);
373    
374                    if (BrowserSnifferUtil.isIe(request)) {
375                            return ContentTypes.TEXT_HTML;
376                    }
377    
378                    return ContentTypes.APPLICATION_JSON;
379            }
380    
381            protected String getRedirect(
382                    ActionRequest actionRequest, ActionResponse actionResponse) {
383    
384                    String redirect = (String)actionRequest.getAttribute(WebKeys.REDIRECT);
385    
386                    if (Validator.isNull(redirect)) {
387                            redirect = ParamUtil.getString(actionRequest, "redirect");
388                    }
389    
390                    return redirect;
391            }
392    
393            protected Method getResourceMethod(String actionName)
394                    throws NoSuchMethodException {
395    
396                    Method method = _resourceMethods.get(actionName);
397    
398                    if (method != null) {
399                            return method;
400                    }
401    
402                    Class<?> clazz = getClass();
403    
404                    method = clazz.getMethod(
405                            actionName, ResourceRequest.class, ResourceResponse.class);
406    
407                    _resourceMethods.put(actionName, method);
408    
409                    return method;
410            }
411    
412            protected ServletContext getServletContext() {
413                    LiferayPortletConfig liferayPortletConfig =
414                            (LiferayPortletConfig)getPortletConfig();
415    
416                    Portlet portlet = liferayPortletConfig.getPortlet();
417    
418                    PortletApp portletApp = portlet.getPortletApp();
419    
420                    return portletApp.getServletContext();
421            }
422    
423            @Override
424            protected String getTitle(RenderRequest renderRequest) {
425                    try {
426                            return PortalUtil.getPortletTitle(renderRequest);
427                    }
428                    catch (Exception e) {
429                            return super.getTitle(renderRequest);
430                    }
431            }
432    
433            protected boolean isAlwaysSendRedirect() {
434                    return alwaysSendRedirect;
435            }
436    
437            protected boolean isEmptySessionMessages(ActionRequest actionRequest) {
438                    if (SessionMessages.isEmpty(actionRequest)) {
439                            return true;
440                    }
441    
442                    int sessionMessagesSize = SessionMessages.size(actionRequest);
443    
444                    String portletId = PortalUtil.getPortletId(actionRequest);
445    
446                    for (String suffix : _IGNORED_SESSION_MESSAGE_SUFFIXES) {
447                            if (SessionMessages.contains(actionRequest, portletId + suffix)) {
448                                    sessionMessagesSize--;
449                            }
450                    }
451    
452                    if (sessionMessagesSize == 0) {
453                            return true;
454                    }
455    
456                    return false;
457            }
458    
459            protected boolean isProcessActionRequest(ActionRequest actionRequest) {
460                    return isProcessPortletRequest(actionRequest);
461            }
462    
463            protected boolean isProcessPortletRequest(PortletRequest portletRequest) {
464                    return _PROCESS_PORTLET_REQUEST;
465            }
466    
467            protected boolean isProcessRenderRequest(RenderRequest renderRequest) {
468                    return isProcessPortletRequest(renderRequest);
469            }
470    
471            protected boolean isProcessResourceRequest(
472                    ResourceRequest resourceRequest) {
473    
474                    return isProcessPortletRequest(resourceRequest);
475            }
476    
477            protected boolean isSessionErrorException(Throwable cause) {
478                    if (_log.isDebugEnabled()) {
479                            _log.debug(cause, cause);
480                    }
481    
482                    if (cause instanceof PortalException) {
483                            return true;
484                    }
485    
486                    return false;
487            }
488    
489            protected void sendRedirect(
490                            ActionRequest actionRequest, ActionResponse actionResponse)
491                    throws IOException {
492    
493                    String redirect = getRedirect(actionRequest, actionResponse);
494    
495                    if (Validator.isNotNull(redirect)) {
496                            actionResponse.sendRedirect(redirect);
497                    }
498            }
499    
500            protected String translate(PortletRequest portletRequest, String key) {
501                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
502                            WebKeys.THEME_DISPLAY);
503    
504                    ResourceBundle resourceBundle = getResourceBundle(
505                            themeDisplay.getLocale());
506    
507                    return LanguageUtil.get(resourceBundle, key);
508            }
509    
510            protected String translate(
511                    PortletRequest portletRequest, String key, Object... arguments) {
512    
513                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
514                            WebKeys.THEME_DISPLAY);
515    
516                    ResourceBundle resourceBundle = getResourceBundle(
517                            themeDisplay.getLocale());
518    
519                    return LanguageUtil.format(resourceBundle, key, arguments);
520            }
521    
522            protected void writeJSON(
523                            PortletRequest portletRequest, ActionResponse actionResponse,
524                            Object json)
525                    throws IOException {
526    
527                    HttpServletResponse response = PortalUtil.getHttpServletResponse(
528                            actionResponse);
529    
530                    response.setContentType(getJSONContentType(portletRequest));
531    
532                    ServletResponseUtil.write(response, json.toString());
533    
534                    response.flushBuffer();
535            }
536    
537            protected void writeJSON(
538                            PortletRequest portletRequest, MimeResponse mimeResponse,
539                            Object json)
540                    throws IOException {
541    
542                    mimeResponse.setContentType(getJSONContentType(portletRequest));
543    
544                    PortletResponseUtil.write(mimeResponse, json.toString());
545    
546                    mimeResponse.flushBuffer();
547            }
548    
549            protected boolean addProcessActionSuccessMessage;
550            protected boolean alwaysSendRedirect;
551    
552            private static final String[] _IGNORED_SESSION_MESSAGE_SUFFIXES = {
553                    SessionMessages.KEY_SUFFIX_DELETE_SUCCESS_DATA,
554                    SessionMessages.KEY_SUFFIX_FORCE_SEND_REDIRECT,
555                    SessionMessages.KEY_SUFFIX_HIDE_DEFAULT_ERROR_MESSAGE,
556                    SessionMessages.KEY_SUFFIX_HIDE_DEFAULT_SUCCESS_MESSAGE,
557                    SessionMessages.KEY_SUFFIX_REFRESH_PORTLET
558            };
559    
560            private static final boolean _PROCESS_PORTLET_REQUEST = true;
561    
562            private static final Log _log = LogFactoryUtil.getLog(LiferayPortlet.class);
563    
564            private final Map<String, Method> _actionMethods =
565                    new ConcurrentHashMap<>();
566            private final Map<String, Method> _resourceMethods =
567                    new ConcurrentHashMap<>();
568    
569    }