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                    if (SessionMessages.contains(
445                                    actionRequest,
446                                    PortalUtil.getPortletId(actionRequest) +
447                                            SessionMessages.KEY_SUFFIX_DELETE_SUCCESS_DATA)) {
448    
449                            sessionMessagesSize--;
450                    }
451    
452                    if (SessionMessages.contains(
453                                    actionRequest,
454                                    PortalUtil.getPortletId(actionRequest) +
455                                            SessionMessages.KEY_SUFFIX_FORCE_SEND_REDIRECT)) {
456    
457                            sessionMessagesSize--;
458                    }
459    
460                    if (SessionMessages.contains(
461                                    actionRequest,
462                                    PortalUtil.getPortletId(actionRequest) +
463                                            SessionMessages.KEY_SUFFIX_HIDE_DEFAULT_ERROR_MESSAGE)) {
464    
465                            sessionMessagesSize--;
466                    }
467    
468                    if (SessionMessages.contains(
469                                    actionRequest,
470                                    PortalUtil.getPortletId(actionRequest) +
471                                            SessionMessages.KEY_SUFFIX_HIDE_DEFAULT_SUCCESS_MESSAGE)) {
472    
473                            sessionMessagesSize--;
474                    }
475    
476                    if (sessionMessagesSize == 0) {
477                            return true;
478                    }
479    
480                    return false;
481            }
482    
483            protected boolean isProcessActionRequest(ActionRequest actionRequest) {
484                    return isProcessPortletRequest(actionRequest);
485            }
486    
487            protected boolean isProcessPortletRequest(PortletRequest portletRequest) {
488                    return _PROCESS_PORTLET_REQUEST;
489            }
490    
491            protected boolean isProcessRenderRequest(RenderRequest renderRequest) {
492                    return isProcessPortletRequest(renderRequest);
493            }
494    
495            protected boolean isProcessResourceRequest(
496                    ResourceRequest resourceRequest) {
497    
498                    return isProcessPortletRequest(resourceRequest);
499            }
500    
501            protected boolean isSessionErrorException(Throwable cause) {
502                    if (_log.isDebugEnabled()) {
503                            _log.debug(cause, cause);
504                    }
505    
506                    if (cause instanceof PortalException) {
507                            return true;
508                    }
509    
510                    return false;
511            }
512    
513            protected void sendRedirect(
514                            ActionRequest actionRequest, ActionResponse actionResponse)
515                    throws IOException {
516    
517                    String redirect = getRedirect(actionRequest, actionResponse);
518    
519                    if (Validator.isNotNull(redirect)) {
520                            actionResponse.sendRedirect(redirect);
521                    }
522            }
523    
524            protected String translate(PortletRequest portletRequest, String key) {
525                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
526                            WebKeys.THEME_DISPLAY);
527    
528                    ResourceBundle resourceBundle = getResourceBundle(
529                            themeDisplay.getLocale());
530    
531                    return LanguageUtil.get(resourceBundle, key);
532            }
533    
534            protected String translate(
535                    PortletRequest portletRequest, String key, Object... arguments) {
536    
537                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
538                            WebKeys.THEME_DISPLAY);
539    
540                    ResourceBundle resourceBundle = getResourceBundle(
541                            themeDisplay.getLocale());
542    
543                    return LanguageUtil.format(resourceBundle, key, arguments);
544            }
545    
546            protected void writeJSON(
547                            PortletRequest portletRequest, ActionResponse actionResponse,
548                            Object json)
549                    throws IOException {
550    
551                    HttpServletResponse response = PortalUtil.getHttpServletResponse(
552                            actionResponse);
553    
554                    response.setContentType(getJSONContentType(portletRequest));
555    
556                    ServletResponseUtil.write(response, json.toString());
557    
558                    response.flushBuffer();
559            }
560    
561            protected void writeJSON(
562                            PortletRequest portletRequest, MimeResponse mimeResponse,
563                            Object json)
564                    throws IOException {
565    
566                    mimeResponse.setContentType(getJSONContentType(portletRequest));
567    
568                    PortletResponseUtil.write(mimeResponse, json.toString());
569    
570                    mimeResponse.flushBuffer();
571            }
572    
573            protected boolean addProcessActionSuccessMessage;
574            protected boolean alwaysSendRedirect;
575    
576            private static final boolean _PROCESS_PORTLET_REQUEST = true;
577    
578            private static final Log _log = LogFactoryUtil.getLog(LiferayPortlet.class);
579    
580            private final Map<String, Method> _actionMethods =
581                    new ConcurrentHashMap<>();
582            private final Map<String, Method> _resourceMethods =
583                    new ConcurrentHashMap<>();
584    
585    }