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 = SessionMessages.isEmpty(
095                                    actionRequest);
096    
097                            if (emptySessionMessages) {
098                                    addSuccessMessage(actionRequest, actionResponse);
099                            }
100    
101                            if (emptySessionMessages || isAlwaysSendRedirect()) {
102                                    sendRedirect(actionRequest, actionResponse);
103                            }
104                    }
105                    catch (PortletException pe) {
106                            Throwable cause = pe.getCause();
107    
108                            if (isSessionErrorException(cause)) {
109                                    SessionErrors.add(actionRequest, cause.getClass(), cause);
110                            }
111                            else {
112                                    throw pe;
113                            }
114                    }
115            }
116    
117            @Override
118            public void serveResource(
119                            ResourceRequest resourceRequest, ResourceResponse resourceResponse)
120                    throws IOException, PortletException {
121    
122                    if (!isProcessResourceRequest(resourceRequest)) {
123                            return;
124                    }
125    
126                    if (!callResourceMethod(resourceRequest, resourceResponse)) {
127                            return;
128                    }
129    
130                    if (!SessionErrors.isEmpty(resourceRequest)) {
131                            return;
132                    }
133    
134                    if (!SessionMessages.isEmpty(resourceRequest)) {
135                            return;
136                    }
137    
138                    super.serveResource(resourceRequest, resourceResponse);
139            }
140    
141            protected void addSuccessMessage(
142                    ActionRequest actionRequest, ActionResponse actionResponse) {
143    
144                    if (!addProcessActionSuccessMessage) {
145                            return;
146                    }
147    
148                    String successMessage = ParamUtil.getString(
149                            actionRequest, "successMessage");
150    
151                    SessionMessages.add(actionRequest, "requestProcessed", successMessage);
152            }
153    
154            protected boolean callActionMethod(
155                            ActionRequest actionRequest, ActionResponse actionResponse)
156                    throws PortletException {
157    
158                    String actionName = ParamUtil.getString(
159                            actionRequest, ActionRequest.ACTION_NAME);
160    
161                    if (Validator.isNull(actionName) ||
162                            actionName.equals("callActionMethod") ||
163                            actionName.equals("processAction")) {
164    
165                            return false;
166                    }
167    
168                    try {
169                            Method method = getActionMethod(actionName);
170    
171                            method.invoke(this, actionRequest, actionResponse);
172    
173                            return true;
174                    }
175                    catch (NoSuchMethodException nsme) {
176                            try {
177                                    super.processAction(actionRequest, actionResponse);
178    
179                                    return true;
180                            }
181                            catch (Exception e) {
182                                    throw new PortletException(nsme);
183                            }
184                    }
185                    catch (InvocationTargetException ite) {
186                            Throwable cause = ite.getCause();
187    
188                            if (cause != null) {
189                                    throw new PortletException(cause);
190                            }
191                            else {
192                                    throw new PortletException(ite);
193                            }
194                    }
195                    catch (Exception e) {
196                            throw new PortletException(e);
197                    }
198            }
199    
200            protected boolean callResourceMethod(
201                            ResourceRequest resourceRequest, ResourceResponse resourceResponse)
202                    throws PortletException {
203    
204                    String actionName = ParamUtil.getString(
205                            resourceRequest, ActionRequest.ACTION_NAME);
206    
207                    if (Validator.isNull(actionName) ||
208                            actionName.equals("callResourceMethod") ||
209                            actionName.equals("serveResource")) {
210    
211                            return false;
212                    }
213    
214                    try {
215                            Method method = getResourceMethod(actionName);
216    
217                            method.invoke(this, resourceRequest, resourceResponse);
218    
219                            return true;
220                    }
221                    catch (NoSuchMethodException nsme) {
222                            try {
223                                    super.serveResource(resourceRequest, resourceResponse);
224    
225                                    return true;
226                            }
227                            catch (Exception e) {
228                                    throw new PortletException(nsme);
229                            }
230                    }
231                    catch (InvocationTargetException ite) {
232                            Throwable cause = ite.getCause();
233    
234                            if (cause != null) {
235                                    throw new PortletException(cause);
236                            }
237                            else {
238                                    throw new PortletException(ite);
239                            }
240                    }
241                    catch (Exception e) {
242                            throw new PortletException(e);
243                    }
244            }
245    
246            @SuppressWarnings("unused")
247            protected void doAbout(
248                            RenderRequest renderRequest, RenderResponse renderResponse)
249                    throws IOException, PortletException {
250    
251                    throw new PortletException("doAbout method not implemented");
252            }
253    
254            @SuppressWarnings("unused")
255            protected void doConfig(
256                            RenderRequest renderRequest, RenderResponse renderResponse)
257                    throws IOException, PortletException {
258    
259                    throw new PortletException("doConfig method not implemented");
260            }
261    
262            @Override
263            protected void doDispatch(
264                            RenderRequest renderRequest, RenderResponse renderResponse)
265                    throws IOException, PortletException {
266    
267                    if (!isProcessRenderRequest(renderRequest)) {
268                            renderRequest.setAttribute(WebKeys.PORTLET_DECORATE, Boolean.FALSE);
269    
270                            return;
271                    }
272    
273                    WindowState windowState = renderRequest.getWindowState();
274    
275                    if (windowState.equals(WindowState.MINIMIZED)) {
276                            return;
277                    }
278    
279                    PortletMode portletMode = renderRequest.getPortletMode();
280    
281                    if (portletMode.equals(PortletMode.VIEW)) {
282                            doView(renderRequest, renderResponse);
283                    }
284                    else if (portletMode.equals(LiferayPortletMode.ABOUT)) {
285                            doAbout(renderRequest, renderResponse);
286                    }
287                    else if (portletMode.equals(LiferayPortletMode.CONFIG)) {
288                            doConfig(renderRequest, renderResponse);
289                    }
290                    else if (portletMode.equals(PortletMode.EDIT)) {
291                            doEdit(renderRequest, renderResponse);
292                    }
293                    else if (portletMode.equals(LiferayPortletMode.EDIT_DEFAULTS)) {
294                            doEditDefaults(renderRequest, renderResponse);
295                    }
296                    else if (portletMode.equals(LiferayPortletMode.EDIT_GUEST)) {
297                            doEditGuest(renderRequest, renderResponse);
298                    }
299                    else if (portletMode.equals(PortletMode.HELP)) {
300                            doHelp(renderRequest, renderResponse);
301                    }
302                    else if (portletMode.equals(LiferayPortletMode.PREVIEW)) {
303                            doPreview(renderRequest, renderResponse);
304                    }
305                    else if (portletMode.equals(LiferayPortletMode.PRINT)) {
306                            doPrint(renderRequest, renderResponse);
307                    }
308                    else {
309                            throw new PortletException(portletMode.toString());
310                    }
311            }
312    
313            @SuppressWarnings("unused")
314            protected void doEditDefaults(
315                            RenderRequest renderRequest, RenderResponse renderResponse)
316                    throws IOException, PortletException {
317    
318                    throw new PortletException("doEditDefaults method not implemented");
319            }
320    
321            @SuppressWarnings("unused")
322            protected void doEditGuest(
323                            RenderRequest renderRequest, RenderResponse renderResponse)
324                    throws IOException, PortletException {
325    
326                    throw new PortletException("doEditGuest method not implemented");
327            }
328    
329            @SuppressWarnings("unused")
330            protected void doPreview(
331                            RenderRequest renderRequest, RenderResponse renderResponse)
332                    throws IOException, PortletException {
333    
334                    throw new PortletException("doPreview method not implemented");
335            }
336    
337            @SuppressWarnings("unused")
338            protected void doPrint(
339                            RenderRequest renderRequest, RenderResponse renderResponse)
340                    throws IOException, PortletException {
341    
342                    throw new PortletException("doPrint method not implemented");
343            }
344    
345            protected Method getActionMethod(String actionName)
346                    throws NoSuchMethodException {
347    
348                    Method method = _actionMethods.get(actionName);
349    
350                    if (method != null) {
351                            return method;
352                    }
353    
354                    Class<?> clazz = getClass();
355    
356                    method = clazz.getMethod(
357                            actionName, ActionRequest.class, ActionResponse.class);
358    
359                    _actionMethods.put(actionName, method);
360    
361                    return method;
362            }
363    
364            protected String getJSONContentType(PortletRequest portletRequest) {
365                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
366                            portletRequest);
367    
368                    if (BrowserSnifferUtil.isIe(request)) {
369                            return ContentTypes.TEXT_HTML;
370                    }
371    
372                    return ContentTypes.APPLICATION_JSON;
373            }
374    
375            protected String getRedirect(
376                    ActionRequest actionRequest, ActionResponse actionResponse) {
377    
378                    String redirect = (String)actionRequest.getAttribute(WebKeys.REDIRECT);
379    
380                    if (Validator.isNull(redirect)) {
381                            redirect = ParamUtil.getString(actionRequest, "redirect");
382                    }
383    
384                    return redirect;
385            }
386    
387            protected Method getResourceMethod(String actionName)
388                    throws NoSuchMethodException {
389    
390                    Method method = _resourceMethods.get(actionName);
391    
392                    if (method != null) {
393                            return method;
394                    }
395    
396                    Class<?> clazz = getClass();
397    
398                    method = clazz.getMethod(
399                            actionName, ResourceRequest.class, ResourceResponse.class);
400    
401                    _resourceMethods.put(actionName, method);
402    
403                    return method;
404            }
405    
406            protected ServletContext getServletContext() {
407                    LiferayPortletConfig liferayPortletConfig =
408                            (LiferayPortletConfig)getPortletConfig();
409    
410                    Portlet portlet = liferayPortletConfig.getPortlet();
411    
412                    PortletApp portletApp = portlet.getPortletApp();
413    
414                    return portletApp.getServletContext();
415            }
416    
417            @Override
418            protected String getTitle(RenderRequest renderRequest) {
419                    try {
420                            return PortalUtil.getPortletTitle(renderRequest);
421                    }
422                    catch (Exception e) {
423                            return super.getTitle(renderRequest);
424                    }
425            }
426    
427            protected boolean isAlwaysSendRedirect() {
428                    return alwaysSendRedirect;
429            }
430    
431            protected boolean isProcessActionRequest(ActionRequest actionRequest) {
432                    return isProcessPortletRequest(actionRequest);
433            }
434    
435            protected boolean isProcessPortletRequest(PortletRequest portletRequest) {
436                    return _PROCESS_PORTLET_REQUEST;
437            }
438    
439            protected boolean isProcessRenderRequest(RenderRequest renderRequest) {
440                    return isProcessPortletRequest(renderRequest);
441            }
442    
443            protected boolean isProcessResourceRequest(
444                    ResourceRequest resourceRequest) {
445    
446                    return isProcessPortletRequest(resourceRequest);
447            }
448    
449            protected boolean isSessionErrorException(Throwable cause) {
450                    if (_log.isDebugEnabled()) {
451                            _log.debug(cause, cause);
452                    }
453    
454                    if (cause instanceof PortalException) {
455                            return true;
456                    }
457    
458                    return false;
459            }
460    
461            protected void sendRedirect(
462                            ActionRequest actionRequest, ActionResponse actionResponse)
463                    throws IOException {
464    
465                    String redirect = getRedirect(actionRequest, actionResponse);
466    
467                    if (Validator.isNotNull(redirect)) {
468                            actionResponse.sendRedirect(redirect);
469                    }
470            }
471    
472            protected String translate(PortletRequest portletRequest, String key) {
473                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
474                            WebKeys.THEME_DISPLAY);
475    
476                    ResourceBundle resourceBundle = getResourceBundle(
477                            themeDisplay.getLocale());
478    
479                    return LanguageUtil.get(resourceBundle, key);
480            }
481    
482            protected String translate(
483                    PortletRequest portletRequest, String key, Object... arguments) {
484    
485                    ThemeDisplay themeDisplay = (ThemeDisplay)portletRequest.getAttribute(
486                            WebKeys.THEME_DISPLAY);
487    
488                    ResourceBundle resourceBundle = getResourceBundle(
489                            themeDisplay.getLocale());
490    
491                    return LanguageUtil.format(resourceBundle, key, arguments);
492            }
493    
494            protected void writeJSON(
495                            PortletRequest portletRequest, ActionResponse actionResponse,
496                            Object json)
497                    throws IOException {
498    
499                    HttpServletResponse response = PortalUtil.getHttpServletResponse(
500                            actionResponse);
501    
502                    response.setContentType(getJSONContentType(portletRequest));
503    
504                    ServletResponseUtil.write(response, json.toString());
505    
506                    response.flushBuffer();
507            }
508    
509            protected void writeJSON(
510                            PortletRequest portletRequest, MimeResponse mimeResponse,
511                            Object json)
512                    throws IOException {
513    
514                    mimeResponse.setContentType(getJSONContentType(portletRequest));
515    
516                    PortletResponseUtil.write(mimeResponse, json.toString());
517    
518                    mimeResponse.flushBuffer();
519            }
520    
521            protected boolean addProcessActionSuccessMessage;
522            protected boolean alwaysSendRedirect;
523    
524            private static final boolean _PROCESS_PORTLET_REQUEST = true;
525    
526            private static final Log _log = LogFactoryUtil.getLog(LiferayPortlet.class);
527    
528            private final Map<String, Method> _actionMethods =
529                    new ConcurrentHashMap<>();
530            private final Map<String, Method> _resourceMethods =
531                    new ConcurrentHashMap<>();
532    
533    }