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