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