001
014
015 package com.liferay.portal.kernel.portlet.bridges.mvc;
016
017 import com.liferay.portal.kernel.log.Log;
018 import com.liferay.portal.kernel.log.LogFactoryUtil;
019 import com.liferay.portal.kernel.portlet.LiferayPortlet;
020 import com.liferay.portal.kernel.servlet.SessionMessages;
021 import com.liferay.portal.kernel.util.GetterUtil;
022 import com.liferay.portal.kernel.util.ParamUtil;
023 import com.liferay.portal.kernel.util.PortalUtil;
024 import com.liferay.portal.kernel.util.StringPool;
025 import com.liferay.portal.kernel.util.StringUtil;
026 import com.liferay.portal.kernel.util.Validator;
027 import com.liferay.portal.kernel.util.WebKeys;
028
029 import java.io.IOException;
030
031 import java.util.List;
032
033 import javax.portlet.ActionRequest;
034 import javax.portlet.ActionResponse;
035 import javax.portlet.EventRequest;
036 import javax.portlet.EventResponse;
037 import javax.portlet.PortletConfig;
038 import javax.portlet.PortletContext;
039 import javax.portlet.PortletException;
040 import javax.portlet.PortletPreferences;
041 import javax.portlet.PortletRequest;
042 import javax.portlet.PortletRequestDispatcher;
043 import javax.portlet.PortletResponse;
044 import javax.portlet.RenderRequest;
045 import javax.portlet.RenderResponse;
046 import javax.portlet.ResourceRequest;
047 import javax.portlet.ResourceResponse;
048 import javax.portlet.WindowState;
049
050 import javax.servlet.http.HttpServletRequest;
051
052
056 public class MVCPortlet extends LiferayPortlet {
057
058 @Override
059 public void destroy() {
060 super.destroy();
061
062 _mvcActionCommandCache.close();
063 _mvcRenderCommandCache.close();
064 _mvcResourceCommandCache.close();
065 }
066
067 @Override
068 public void doAbout(
069 RenderRequest renderRequest, RenderResponse renderResponse)
070 throws IOException, PortletException {
071
072 include(aboutTemplate, renderRequest, renderResponse);
073 }
074
075 @Override
076 public void doConfig(
077 RenderRequest renderRequest, RenderResponse renderResponse)
078 throws IOException, PortletException {
079
080 include(configTemplate, renderRequest, renderResponse);
081 }
082
083 @Override
084 public void doEdit(
085 RenderRequest renderRequest, RenderResponse renderResponse)
086 throws IOException, PortletException {
087
088 PortletPreferences portletPreferences = renderRequest.getPreferences();
089
090 if (portletPreferences == null) {
091 super.doEdit(renderRequest, renderResponse);
092 }
093 else {
094 include(editTemplate, renderRequest, renderResponse);
095 }
096 }
097
098 @Override
099 public void doEditDefaults(
100 RenderRequest renderRequest, RenderResponse renderResponse)
101 throws IOException, PortletException {
102
103 PortletPreferences portletPreferences = renderRequest.getPreferences();
104
105 if (portletPreferences == null) {
106 super.doEdit(renderRequest, renderResponse);
107 }
108 else {
109 include(editDefaultsTemplate, renderRequest, renderResponse);
110 }
111 }
112
113 @Override
114 public void doEditGuest(
115 RenderRequest renderRequest, RenderResponse renderResponse)
116 throws IOException, PortletException {
117
118 PortletPreferences portletPreferences = renderRequest.getPreferences();
119
120 if (portletPreferences == null) {
121 super.doEdit(renderRequest, renderResponse);
122 }
123 else {
124 include(editGuestTemplate, renderRequest, renderResponse);
125 }
126 }
127
128 @Override
129 public void doHelp(
130 RenderRequest renderRequest, RenderResponse renderResponse)
131 throws IOException, PortletException {
132
133 include(helpTemplate, renderRequest, renderResponse);
134 }
135
136 @Override
137 public void doPreview(
138 RenderRequest renderRequest, RenderResponse renderResponse)
139 throws IOException, PortletException {
140
141 include(previewTemplate, renderRequest, renderResponse);
142 }
143
144 @Override
145 public void doPrint(
146 RenderRequest renderRequest, RenderResponse renderResponse)
147 throws IOException, PortletException {
148
149 include(printTemplate, renderRequest, renderResponse);
150 }
151
152 @Override
153 public void doView(
154 RenderRequest renderRequest, RenderResponse renderResponse)
155 throws IOException, PortletException {
156
157 include(viewTemplate, renderRequest, renderResponse);
158 }
159
160 @Override
161 public void init() throws PortletException {
162 super.init();
163
164 templatePath = _getInitParameter("template-path");
165
166 if (Validator.isNull(templatePath)) {
167 templatePath = StringPool.SLASH;
168 }
169 else if (templatePath.contains(StringPool.BACK_SLASH) ||
170 templatePath.contains(StringPool.DOUBLE_SLASH) ||
171 templatePath.contains(StringPool.PERIOD) ||
172 templatePath.contains(StringPool.SPACE)) {
173
174 throw new PortletException(
175 "template-path " + templatePath + " has invalid characters");
176 }
177 else if (!templatePath.startsWith(StringPool.SLASH) ||
178 !templatePath.endsWith(StringPool.SLASH)) {
179
180 throw new PortletException(
181 "template-path " + templatePath +
182 " must start and end with a /");
183 }
184
185 aboutTemplate = _getInitParameter("about-template");
186 configTemplate = _getInitParameter("config-template");
187 editTemplate = _getInitParameter("edit-template");
188 editDefaultsTemplate = _getInitParameter("edit-defaults-template");
189 editGuestTemplate = _getInitParameter("edit-guest-template");
190 helpTemplate = _getInitParameter("help-template");
191 previewTemplate = _getInitParameter("preview-template");
192 printTemplate = _getInitParameter("print-template");
193 viewTemplate = _getInitParameter("view-template");
194
195 clearRequestParameters = GetterUtil.getBoolean(
196 getInitParameter("clear-request-parameters"));
197 copyRequestParameters = GetterUtil.getBoolean(
198 getInitParameter("copy-request-parameters"), true);
199
200 _mvcActionCommandCache = new MVCCommandCache(
201 MVCActionCommand.EMPTY,
202 getInitParameter("mvc-action-command-package-prefix"),
203 getPortletName(), MVCActionCommand.class.getName(),
204 "ActionCommand");
205 _mvcRenderCommandCache = new MVCCommandCache(
206 MVCRenderCommand.EMPTY,
207 getInitParameter("mvc-render-command-package-prefix"),
208 getPortletName(), MVCRenderCommand.class.getName(),
209 "RenderCommand");
210 _mvcResourceCommandCache = new MVCCommandCache(
211 MVCResourceCommand.EMPTY,
212 getInitParameter("mvc-resource-command-package-prefix"),
213 getPortletName(), MVCResourceCommand.class.getName(),
214 "ResourceCommand");
215 }
216
217
220 @Deprecated
221 public void invokeTaglibDiscussion(
222 ActionRequest actionRequest, ActionResponse actionResponse)
223 throws Exception {
224
225 PortletConfig portletConfig = getPortletConfig();
226
227 PortalUtil.invokeTaglibDiscussion(
228 portletConfig, actionRequest, actionResponse);
229 }
230
231
234 @Deprecated
235 public void invokeTaglibDiscussionPagination(
236 ResourceRequest resourceRequest, ResourceResponse resourceResponse)
237 throws IOException, PortletException {
238
239 PortletConfig portletConfig = getPortletConfig();
240
241 PortalUtil.invokeTaglibDiscussionPagination(
242 portletConfig, resourceRequest, resourceResponse);
243 }
244
245 @Override
246 public void processAction(
247 ActionRequest actionRequest, ActionResponse actionResponse)
248 throws IOException, PortletException {
249
250 super.processAction(actionRequest, actionResponse);
251
252 if (copyRequestParameters) {
253 PortalUtil.copyRequestParameters(actionRequest, actionResponse);
254 }
255 }
256
257 @Override
258 public void render(
259 RenderRequest renderRequest, RenderResponse renderResponse)
260 throws IOException, PortletException {
261
262 invokeHideDefaultSuccessMessage(renderRequest);
263
264 String mvcRenderCommandName = ParamUtil.getString(
265 renderRequest, "mvcRenderCommandName", "/");
266
267 String mvcPath = ParamUtil.getString(renderRequest, "mvcPath");
268
269 if (!mvcRenderCommandName.equals("/") || Validator.isNull(mvcPath)) {
270 MVCRenderCommand mvcRenderCommand =
271 (MVCRenderCommand)_mvcRenderCommandCache.getMVCCommand(
272 mvcRenderCommandName);
273
274 mvcPath = null;
275
276 if (mvcRenderCommand != MVCRenderCommand.EMPTY) {
277 mvcPath = mvcRenderCommand.render(
278 renderRequest, renderResponse);
279 }
280
281 if (MVCRenderConstants.MVC_PATH_VALUE_SKIP_DISPATCH.equals(
282 mvcPath)) {
283
284 return;
285 }
286
287 renderRequest.setAttribute(
288 getMVCPathAttributeName(renderResponse.getNamespace()),
289 mvcPath);
290 }
291
292 super.render(renderRequest, renderResponse);
293 }
294
295 @Override
296 public void serveResource(
297 ResourceRequest resourceRequest, ResourceResponse resourceResponse)
298 throws IOException, PortletException {
299
300 invokeHideDefaultSuccessMessage(resourceRequest);
301
302 String path = getPath(resourceRequest, resourceResponse);
303
304 if (path != null) {
305 include(
306 path, resourceRequest, resourceResponse,
307 PortletRequest.RESOURCE_PHASE);
308 }
309
310 boolean invokeTaglibDiscussion = GetterUtil.getBoolean(
311 resourceRequest.getParameter("invokeTaglibDiscussion"));
312
313 if (invokeTaglibDiscussion) {
314 invokeTaglibDiscussionPagination(resourceRequest, resourceResponse);
315 }
316 else {
317 super.serveResource(resourceRequest, resourceResponse);
318 }
319 }
320
321 @Override
322 protected boolean callActionMethod(
323 ActionRequest actionRequest, ActionResponse actionResponse)
324 throws PortletException {
325
326 try {
327 checkPermissions(actionRequest);
328 }
329 catch (Exception e) {
330 throw new PortletException(e);
331 }
332
333 String[] actionNames = ParamUtil.getParameterValues(
334 actionRequest, ActionRequest.ACTION_NAME);
335
336 String actionName = StringUtil.merge(actionNames);
337
338 if (!actionName.contains(StringPool.COMMA)) {
339 MVCActionCommand mvcActionCommand =
340 (MVCActionCommand)_mvcActionCommandCache.getMVCCommand(
341 actionName);
342
343 if (mvcActionCommand != MVCActionCommand.EMPTY) {
344 if (mvcActionCommand instanceof FormMVCActionCommand) {
345 FormMVCActionCommand formMVCActionCommand =
346 (FormMVCActionCommand)mvcActionCommand;
347
348 if (!formMVCActionCommand.validateForm(
349 actionRequest, actionResponse)) {
350
351 return false;
352 }
353 }
354
355 return mvcActionCommand.processAction(
356 actionRequest, actionResponse);
357 }
358 }
359 else {
360 List<MVCActionCommand> mvcActionCommands =
361 (List<MVCActionCommand>)_mvcActionCommandCache.getMVCCommands(
362 actionName);
363
364 if (!mvcActionCommands.isEmpty()) {
365 boolean valid = true;
366
367 for (MVCActionCommand mvcActionCommand : mvcActionCommands) {
368 if (mvcActionCommand instanceof FormMVCActionCommand) {
369 FormMVCActionCommand formMVCActionCommand =
370 (FormMVCActionCommand)mvcActionCommand;
371
372 valid &= formMVCActionCommand.validateForm(
373 actionRequest, actionResponse);
374 }
375 }
376
377 if (!valid) {
378 return false;
379 }
380
381 for (MVCActionCommand mvcActionCommand : mvcActionCommands) {
382 if (!mvcActionCommand.processAction(
383 actionRequest, actionResponse)) {
384
385 return false;
386 }
387 }
388
389 return true;
390 }
391 }
392
393 return super.callActionMethod(actionRequest, actionResponse);
394 }
395
396 @Override
397 protected boolean callResourceMethod(
398 ResourceRequest resourceRequest, ResourceResponse resourceResponse)
399 throws PortletException {
400
401 try {
402 checkPermissions(resourceRequest);
403 }
404 catch (Exception e) {
405 throw new PortletException(e);
406 }
407
408 String resourceID = GetterUtil.getString(
409 resourceRequest.getResourceID());
410
411 if (!resourceID.contains(StringPool.COMMA)) {
412 MVCResourceCommand mvcResourceCommand =
413 (MVCResourceCommand)_mvcResourceCommandCache.getMVCCommand(
414 resourceID);
415
416 if (mvcResourceCommand != MVCResourceCommand.EMPTY) {
417 return mvcResourceCommand.serveResource(
418 resourceRequest, resourceResponse);
419 }
420 }
421 else {
422 List<MVCResourceCommand> mvcResourceCommands =
423 (List<MVCResourceCommand>)
424 _mvcResourceCommandCache.getMVCCommands(resourceID);
425
426 if (!mvcResourceCommands.isEmpty()) {
427 for (MVCResourceCommand mvcResourceCommand :
428 mvcResourceCommands) {
429
430 if (!mvcResourceCommand.serveResource(
431 resourceRequest, resourceResponse)) {
432
433 return false;
434 }
435 }
436
437 return true;
438 }
439 }
440
441 return super.callResourceMethod(resourceRequest, resourceResponse);
442 }
443
444 protected void checkPath(String path) throws PortletException {
445 if (Validator.isNotNull(path) &&
446 (!path.startsWith(templatePath) ||
447 !PortalUtil.isValidResourceId(path) ||
448 !Validator.isFilePath(path, false))) {
449
450 throw new PortletException(
451 "Path " + path + " is not accessible by this portlet");
452 }
453 }
454
455 protected void checkPermissions(PortletRequest portletRequest)
456 throws Exception {
457 }
458
459 @Override
460 protected void doDispatch(
461 RenderRequest renderRequest, RenderResponse renderResponse)
462 throws IOException, PortletException {
463
464 String path = getPath(renderRequest, renderResponse);
465
466 if (path != null) {
467 if (!isProcessRenderRequest(renderRequest)) {
468 renderRequest.setAttribute(
469 WebKeys.PORTLET_DECORATE, Boolean.FALSE);
470
471 return;
472 }
473
474 WindowState windowState = renderRequest.getWindowState();
475
476 if (windowState.equals(WindowState.MINIMIZED)) {
477 return;
478 }
479
480 include(path, renderRequest, renderResponse);
481 }
482 else {
483 super.doDispatch(renderRequest, renderResponse);
484 }
485 }
486
487 protected String getMVCPathAttributeName(String namespace) {
488 return namespace.concat(StringPool.PERIOD).concat(
489 MVCRenderConstants.MVC_PATH_REQUEST_ATTRIBUTE_NAME);
490 }
491
492 protected String getPath(
493 PortletRequest portletRequest, PortletResponse portletResponse) {
494
495 String mvcPath = portletRequest.getParameter("mvcPath");
496
497 if (mvcPath == null) {
498 mvcPath = (String)portletRequest.getAttribute(
499 getMVCPathAttributeName(portletResponse.getNamespace()));
500 }
501
502
503
504 if (mvcPath == null) {
505 mvcPath = portletRequest.getParameter("jspPage");
506 }
507
508 return mvcPath;
509 }
510
511 protected void hideDefaultErrorMessage(PortletRequest portletRequest) {
512 SessionMessages.add(
513 portletRequest,
514 PortalUtil.getPortletId(portletRequest) +
515 SessionMessages.KEY_SUFFIX_HIDE_DEFAULT_ERROR_MESSAGE);
516 }
517
518 protected void hideDefaultSuccessMessage(PortletRequest portletRequest) {
519 SessionMessages.add(
520 portletRequest,
521 PortalUtil.getPortletId(portletRequest) +
522 SessionMessages.KEY_SUFFIX_HIDE_DEFAULT_SUCCESS_MESSAGE);
523 }
524
525 protected void include(
526 String path, ActionRequest actionRequest,
527 ActionResponse actionResponse)
528 throws IOException, PortletException {
529
530 include(
531 path, actionRequest, actionResponse, PortletRequest.ACTION_PHASE);
532 }
533
534 protected void include(
535 String path, EventRequest eventRequest, EventResponse eventResponse)
536 throws IOException, PortletException {
537
538 include(path, eventRequest, eventResponse, PortletRequest.EVENT_PHASE);
539 }
540
541 protected void include(
542 String path, PortletRequest portletRequest,
543 PortletResponse portletResponse, String lifecycle)
544 throws IOException, PortletException {
545
546 HttpServletRequest httpServletRequest =
547 PortalUtil.getHttpServletRequest(portletRequest);
548
549 PortletContext portletContext =
550 (PortletContext)httpServletRequest.getAttribute(
551 MVCRenderConstants.
552 PORTLET_CONTEXT_OVERRIDE_REQUEST_ATTIBUTE_NAME_PREFIX +
553 path);
554
555 if (portletContext == null) {
556 portletContext = getPortletContext();
557 }
558
559 PortletRequestDispatcher portletRequestDispatcher =
560 portletContext.getRequestDispatcher(path);
561
562 if (portletRequestDispatcher == null) {
563 _log.error(path + " is not a valid include");
564 }
565 else {
566 checkPath(path);
567
568 portletRequestDispatcher.include(portletRequest, portletResponse);
569 }
570
571 if (clearRequestParameters) {
572 if (lifecycle.equals(PortletRequest.RENDER_PHASE)) {
573 portletResponse.setProperty(
574 "clear-request-parameters", Boolean.TRUE.toString());
575 }
576 }
577 }
578
579 protected void include(
580 String path, RenderRequest renderRequest,
581 RenderResponse renderResponse)
582 throws IOException, PortletException {
583
584 include(
585 path, renderRequest, renderResponse, PortletRequest.RENDER_PHASE);
586 }
587
588 protected void include(
589 String path, ResourceRequest resourceRequest,
590 ResourceResponse resourceResponse)
591 throws IOException, PortletException {
592
593 include(
594 path, resourceRequest, resourceResponse,
595 PortletRequest.RESOURCE_PHASE);
596 }
597
598 protected void invokeHideDefaultSuccessMessage(
599 PortletRequest portletRequest) {
600
601 boolean hideDefaultSuccessMessage = ParamUtil.getBoolean(
602 portletRequest, "hideDefaultSuccessMessage");
603
604 if (hideDefaultSuccessMessage) {
605 hideDefaultSuccessMessage(portletRequest);
606 }
607 }
608
609 protected String aboutTemplate;
610 protected boolean clearRequestParameters;
611 protected String configTemplate;
612 protected boolean copyRequestParameters;
613 protected String editDefaultsTemplate;
614 protected String editGuestTemplate;
615 protected String editTemplate;
616 protected String helpTemplate;
617 protected String previewTemplate;
618 protected String printTemplate;
619 protected String templatePath;
620 protected String viewTemplate;
621
622 private String _getInitParameter(String name) {
623 String value = getInitParameter(name);
624
625 if (value != null) {
626 return value;
627 }
628
629
630
631 if (name.equals("template-path")) {
632 return getInitParameter("jsp-path");
633 }
634 else if (name.endsWith("-template")) {
635 name = name.substring(0, name.length() - 9) + "-jsp";
636
637 return getInitParameter(name);
638 }
639
640 return null;
641 }
642
643 private static final Log _log = LogFactoryUtil.getLog(MVCPortlet.class);
644
645 private MVCCommandCache _mvcActionCommandCache;
646 private MVCCommandCache _mvcRenderCommandCache;
647 private MVCCommandCache _mvcResourceCommandCache;
648
649 }