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