1
14
15 package com.liferay.portlet;
16
17 import com.liferay.portal.kernel.language.LanguageUtil;
18 import com.liferay.portal.kernel.log.Log;
19 import com.liferay.portal.kernel.log.LogFactoryUtil;
20 import com.liferay.portal.kernel.portlet.LiferayPortletRequest;
21 import com.liferay.portal.kernel.portlet.LiferayPortletResponse;
22 import com.liferay.portal.kernel.portlet.PortletFilterUtil;
23 import com.liferay.portal.kernel.servlet.PortletServlet;
24 import com.liferay.portal.kernel.servlet.StringServletResponse;
25 import com.liferay.portal.kernel.util.ClassUtil;
26 import com.liferay.portal.kernel.util.GetterUtil;
27 import com.liferay.portal.kernel.util.JavaConstants;
28 import com.liferay.portal.kernel.util.StringBundler;
29 import com.liferay.portal.kernel.util.StringPool;
30 import com.liferay.portal.kernel.util.Time;
31 import com.liferay.portal.model.Layout;
32 import com.liferay.portal.tools.deploy.PortletDeployer;
33 import com.liferay.portal.util.WebKeys;
34
35 import java.io.IOException;
36
37 import java.util.ArrayList;
38 import java.util.HashMap;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Set;
42 import java.util.concurrent.ConcurrentHashMap;
43
44 import javax.portlet.ActionRequest;
45 import javax.portlet.ActionResponse;
46 import javax.portlet.EventRequest;
47 import javax.portlet.EventResponse;
48 import javax.portlet.Portlet;
49 import javax.portlet.PortletConfig;
50 import javax.portlet.PortletContext;
51 import javax.portlet.PortletException;
52 import javax.portlet.PortletRequest;
53 import javax.portlet.PortletSession;
54 import javax.portlet.RenderRequest;
55 import javax.portlet.RenderResponse;
56 import javax.portlet.ResourceRequest;
57 import javax.portlet.ResourceResponse;
58 import javax.portlet.filter.ActionFilter;
59 import javax.portlet.filter.EventFilter;
60 import javax.portlet.filter.FilterChain;
61 import javax.portlet.filter.PortletFilter;
62 import javax.portlet.filter.RenderFilter;
63 import javax.portlet.filter.ResourceFilter;
64
65 import javax.servlet.RequestDispatcher;
66 import javax.servlet.ServletException;
67 import javax.servlet.http.HttpServletRequest;
68 import javax.servlet.http.HttpServletResponse;
69 import javax.servlet.http.HttpSession;
70
71 import org.apache.commons.lang.time.StopWatch;
72
73
79 public class InvokerPortletImpl implements InvokerPortlet {
80
81 public static void clearResponse(
82 HttpSession session, long plid, String portletId, String languageId) {
83
84 String sesResponseId = encodeResponseKey(plid, portletId, languageId);
85
86 getResponses(session).remove(sesResponseId);
87 }
88
89 public static void clearResponses(HttpSession session) {
90 getResponses(session).clear();
91 }
92
93 public static void clearResponses(PortletSession session) {
94 getResponses(session).clear();
95 }
96
97 public static String encodeResponseKey(
98 long plid, String portletId, String languageId) {
99
100 StringBundler sb = new StringBundler(5);
101
102 sb.append(plid);
103 sb.append(StringPool.UNDERLINE);
104 sb.append(portletId);
105 sb.append(StringPool.UNDERLINE);
106 sb.append(languageId);
107
108 return sb.toString();
109 }
110
111 public static Map<String, InvokerPortletResponse> getResponses(
112 HttpSession session) {
113
114 Map<String, InvokerPortletResponse> responses =
115 (Map<String, InvokerPortletResponse>)session.getAttribute(
116 WebKeys.CACHE_PORTLET_RESPONSES);
117
118 if (responses == null) {
119 responses = new ConcurrentHashMap<String, InvokerPortletResponse>();
120
121 session.setAttribute(WebKeys.CACHE_PORTLET_RESPONSES, responses);
122 }
123
124 return responses;
125 }
126
127 public static Map<String, InvokerPortletResponse> getResponses(
128 PortletSession portletSession) {
129
130 return getResponses(
131 ((PortletSessionImpl)portletSession).getHttpSession());
132 }
133
134 public InvokerPortlet create(
135 com.liferay.portal.model.Portlet portletModel, Portlet portlet,
136 PortletContext portletContext)
137 throws PortletException {
138
139 try {
140 InvokerPortlet invokerPortlet = (InvokerPortlet)clone();
141
142 invokerPortlet.prepare(portletModel, portlet, portletContext);
143
144 return invokerPortlet;
145 }
146 catch (PortletException pe) {
147 throw pe;
148 }
149 catch (Exception e) {
150 throw new PortletException(e);
151 }
152 }
153
154 public InvokerPortlet create(
155 com.liferay.portal.model.Portlet portletModel, Portlet portlet,
156 PortletConfig portletConfig, PortletContext portletContext,
157 boolean checkAuthToken, boolean facesPortlet, boolean strutsPortlet,
158 boolean strutsBridgePortlet)
159 throws PortletException {
160
161 try {
162 InvokerPortlet invokerPortlet = (InvokerPortlet)clone();
163
164 invokerPortlet.prepare(
165 portletModel, portlet, portletConfig, portletContext,
166 checkAuthToken, facesPortlet, strutsPortlet,
167 strutsBridgePortlet);
168
169 return invokerPortlet;
170 }
171 catch (PortletException pe) {
172 throw pe;
173 }
174 catch (Exception e) {
175 throw new PortletException(e);
176 }
177 }
178
179 public void destroy() {
180 if (_destroyable) {
181 Thread currentThread = Thread.currentThread();
182
183 ClassLoader contextClassLoader =
184 currentThread.getContextClassLoader();
185
186 ClassLoader portletClassLoader = getPortletClassLoader();
187
188 try {
189 if (portletClassLoader != null) {
190 currentThread.setContextClassLoader(portletClassLoader);
191 }
192
193 removePortletFilters();
194
195 _portlet.destroy();
196 }
197 finally {
198 if (portletClassLoader != null) {
199 currentThread.setContextClassLoader(contextClassLoader);
200 }
201 }
202 }
203
204 _destroyable = false;
205 }
206
207 public Portlet getPortlet() {
208 return _portlet;
209 }
210
211 public ClassLoader getPortletClassLoader() {
212 return (ClassLoader)_portletContextImpl.getAttribute(
213 PortletServlet.PORTLET_CLASS_LOADER);
214 }
215
216 public PortletConfigImpl getPortletConfig() {
217 return _portletConfigImpl;
218 }
219
220 public PortletContextImpl getPortletContext() {
221 return _portletContextImpl;
222 }
223
224 public Portlet getPortletInstance() {
225 return _portlet;
226 }
227
228 public Integer getExpCache() {
229 return _expCache;
230 }
231
232 public void init(PortletConfig portletConfig) throws PortletException {
233 _portletConfigImpl = (PortletConfigImpl)portletConfig;
234
235 Thread currentThread = Thread.currentThread();
236
237 ClassLoader contextClassLoader = currentThread.getContextClassLoader();
238
239 ClassLoader portletClassLoader = getPortletClassLoader();
240
241 try {
242 if (portletClassLoader != null) {
243 currentThread.setContextClassLoader(portletClassLoader);
244 }
245
246 _portlet.init(portletConfig);
247 }
248 finally {
249 if (portletClassLoader != null) {
250 currentThread.setContextClassLoader(contextClassLoader);
251 }
252 }
253
254 _destroyable = true;
255 }
256
257 public boolean isCheckAuthToken() {
258 return _checkAuthToken;
259 }
260
261 public boolean isDestroyable() {
262 return _destroyable;
263 }
264
265 public boolean isFacesPortlet() {
266 return _facesPortlet;
267 }
268
269 public boolean isStrutsBridgePortlet() {
270 return _strutsBridgePortlet;
271 }
272
273 public boolean isStrutsPortlet() {
274 return _strutsPortlet;
275 }
276
277 public void prepare(
278 com.liferay.portal.model.Portlet portletModel, Portlet portlet,
279 PortletContext portletContext)
280 throws PortletException {
281
282 _portletModel = portletModel;
283 _portletId = _portletModel.getPortletId();
284 _portlet = portlet;
285 _portletContextImpl = (PortletContextImpl)portletContext;
286
287 if (_log.isDebugEnabled()) {
288 _log.debug(
289 "Create root cache wrapper for " +
290 _portletContextImpl.getPortlet().getPortletId());
291 }
292
293 Map<String, String> initParams = portletModel.getInitParams();
294
295 _checkAuthToken = GetterUtil.getBoolean(
296 initParams.get("check-auth-token"), true);
297
298 if (ClassUtil.isSubclass(
299 _portlet.getClass(), PortletDeployer.JSF_MYFACES) ||
300 ClassUtil.isSubclass(
301 _portlet.getClass(), PortletDeployer.JSF_STANDARD) ||
302 ClassUtil.isSubclass(
303 _portlet.getClass(), PortletDeployer.JSF_SUN)) {
304
305 _facesPortlet = true;
306 }
307
308 _strutsPortlet = ClassUtil.isSubclass(
309 portlet.getClass(), StrutsPortlet.class);
310 _strutsBridgePortlet = ClassUtil.isSubclass(
311 portlet.getClass(),
312 "org.apache.portals.bridges.struts.StrutsPortlet");
313 _expCache = portletModel.getExpCache();
314 setPortletFilters();
315 }
316
317 public void prepare(
318 com.liferay.portal.model.Portlet portletModel, Portlet portlet,
319 PortletConfig portletConfig, PortletContext portletContext,
320 boolean checkAuthToken, boolean facesPortlet, boolean strutsPortlet,
321 boolean strutsBridgePortlet)
322 throws PortletException {
323
324
326 _portletModel = portletModel;
327 _portlet = portlet;
328 _portletId = _portletModel.getPortletId();
329 _portletContextImpl = (PortletContextImpl)portletContext;
330 _checkAuthToken = checkAuthToken;
331 _facesPortlet = facesPortlet;
332 _strutsPortlet = strutsPortlet;
333 _strutsBridgePortlet = strutsBridgePortlet;
334 _expCache = portletModel.getExpCache();
335 setPortletFilters();
336
337 if (_log.isDebugEnabled()) {
338 _log.debug(
339 "Create instance cache wrapper for " +
340 _portletContextImpl.getPortlet().getPortletId());
341 }
342
343
345 _portletConfigImpl = (PortletConfigImpl)portletConfig;
346 }
347
348 public void processAction(
349 ActionRequest actionRequest, ActionResponse actionResponse)
350 throws IOException {
351
352 StopWatch stopWatch = null;
353
354 if (_log.isDebugEnabled()) {
355 stopWatch = new StopWatch();
356
357 stopWatch.start();
358 }
359
360 try {
361 invokeAction(actionRequest, actionResponse);
362 }
363 catch (PortletException pe) {
364 actionRequest.setAttribute(
365 _portletId + PortletException.class.getName(), pe);
366 }
367
368 if (_log.isDebugEnabled()) {
369 _log.debug(
370 "processAction for " + _portletId + " takes " +
371 stopWatch.getTime() + " ms");
372 }
373 }
374
375 public void processEvent(
376 EventRequest eventRequest, EventResponse eventResponse)
377 throws IOException, PortletException {
378
379 StopWatch stopWatch = null;
380
381 if (_log.isDebugEnabled()) {
382 stopWatch = new StopWatch();
383
384 stopWatch.start();
385 }
386
387 invokeEvent(eventRequest, eventResponse);
388
389 if (_log.isDebugEnabled()) {
390 _log.debug(
391 "processEvent for " + _portletId + " takes " +
392 stopWatch.getTime() + " ms");
393 }
394 }
395
396 public void render(
397 RenderRequest renderRequest, RenderResponse renderResponse)
398 throws IOException, PortletException {
399
400 PortletException portletException =
401 (PortletException)renderRequest.getAttribute(
402 _portletId + PortletException.class.getName());
403
404 if (portletException != null) {
405 throw portletException;
406 }
407
408 StopWatch stopWatch = null;
409
410 if (_log.isDebugEnabled()) {
411 stopWatch = new StopWatch();
412
413 stopWatch.start();
414 }
415
416 String remoteUser = renderRequest.getRemoteUser();
417
418 if ((remoteUser == null) || (_expCache == null) ||
419 (_expCache.intValue() == 0)) {
420
421 invokeRender(renderRequest, renderResponse);
422 }
423 else {
424 RenderResponseImpl renderResponseImpl =
425 (RenderResponseImpl)renderResponse;
426
427 StringServletResponse stringResponse = (StringServletResponse)
428 renderResponseImpl.getHttpServletResponse();
429
430 PortletSession portletSession = renderRequest.getPortletSession();
431
432 long now = System.currentTimeMillis();
433
434 Layout layout = (Layout)renderRequest.getAttribute(WebKeys.LAYOUT);
435
436 Map<String, InvokerPortletResponse> sessionResponses =
437 getResponses(portletSession);
438
439 String sessionResponseId = encodeResponseKey(
440 layout.getPlid(), _portletId,
441 LanguageUtil.getLanguageId(renderRequest));
442
443 InvokerPortletResponse response = sessionResponses.get(
444 sessionResponseId);
445
446 if (response == null) {
447 String title = invokeRender(renderRequest, renderResponse);
448
449 response = new InvokerPortletResponse(
450 title, stringResponse.getString(),
451 now + Time.SECOND * _expCache.intValue());
452
453 sessionResponses.put(sessionResponseId, response);
454 }
455 else if ((response.getTime() < now) &&
456 (_expCache.intValue() > 0)) {
457
458 String title = invokeRender(renderRequest, renderResponse);
459
460 response.setTitle(title);
461 response.setContent(stringResponse.getString());
462 response.setTime(now + Time.SECOND * _expCache.intValue());
463 }
464 else {
465 renderResponseImpl.setTitle(response.getTitle());
466 stringResponse.getWriter().print(response.getContent());
467 }
468 }
469
470 Map<String, String[]> properties =
471 ((RenderResponseImpl)renderResponse).getProperties();
472
473 if (properties.containsKey("clear-request-parameters")) {
474 Map<String, String[]> renderParameters =
475 ((RenderRequestImpl)renderRequest).getRenderParameters();
476
477 renderParameters.clear();
478 }
479
480 if (_log.isDebugEnabled()) {
481 _log.debug(
482 "render for " + _portletId + " takes " + stopWatch.getTime() +
483 " ms");
484 }
485 }
486
487 public void serveResource(
488 ResourceRequest resourceRequest, ResourceResponse resourceResponse)
489 throws IOException {
490
491 StopWatch stopWatch = null;
492
493 if (_log.isDebugEnabled()) {
494 stopWatch = new StopWatch();
495
496 stopWatch.start();
497 }
498
499 try {
500 invokeResource(resourceRequest, resourceResponse);
501 }
502 catch (PortletException pe) {
503 resourceRequest.setAttribute(
504 _portletId + PortletException.class.getName(), pe);
505 }
506
507 if (_log.isDebugEnabled()) {
508 _log.debug(
509 "serveResource for " + _portletId + " takes " +
510 stopWatch.getTime() + " ms");
511 }
512 }
513
514 public void setPortletFilters() throws PortletException {
515 removePortletFilters();
516
517 Map<String, com.liferay.portal.model.PortletFilter> portletFilters =
518 _portletModel.getPortletFilters();
519
520 for (Map.Entry<String, com.liferay.portal.model.PortletFilter> entry :
521 portletFilters.entrySet()) {
522
523 com.liferay.portal.model.PortletFilter portletFilterModel =
524 entry.getValue();
525
526 PortletFilter portletFilter = PortletFilterFactory.create(
527 portletFilterModel, _portletContextImpl);
528
529 Set<String> lifecycles = portletFilterModel.getLifecycles();
530
531 if (lifecycles.contains(PortletRequest.ACTION_PHASE)) {
532 List<ActionFilter> actionFilters = _actionFiltersMap.get(
533 _portletId);
534
535 if (actionFilters == null) {
536 actionFilters = new ArrayList<ActionFilter>();
537 }
538
539 actionFilters.add((ActionFilter)portletFilter);
540
541 _actionFiltersMap.put(_portletId, actionFilters);
542 }
543
544 if (lifecycles.contains(PortletRequest.EVENT_PHASE)) {
545 List<EventFilter> eventFilters = _eventFiltersMap.get(
546 _portletId);
547
548 if (eventFilters == null) {
549 eventFilters = new ArrayList<EventFilter>();
550 }
551
552 eventFilters.add((EventFilter)portletFilter);
553
554 _eventFiltersMap.put(_portletId, eventFilters);
555 }
556
557 if (lifecycles.contains(PortletRequest.RENDER_PHASE)) {
558 List<RenderFilter> renderFilters = _renderFiltersMap.get(
559 _portletId);
560
561 if (renderFilters == null) {
562 renderFilters = new ArrayList<RenderFilter>();
563 }
564
565 renderFilters.add((RenderFilter)portletFilter);
566
567 _renderFiltersMap.put(_portletId, renderFilters);
568 }
569
570 if (lifecycles.contains(PortletRequest.RESOURCE_PHASE)) {
571 List<ResourceFilter> resourceFilters = _resourceFiltersMap.get(
572 _portletId);
573
574 if (resourceFilters == null) {
575 resourceFilters = new ArrayList<ResourceFilter>();
576 }
577
578 resourceFilters.add((ResourceFilter)portletFilter);
579
580 _resourceFiltersMap.put(_portletId, resourceFilters);
581 }
582 }
583 }
584
585 protected void invoke(
586 LiferayPortletRequest portletRequest,
587 LiferayPortletResponse portletResponse, String lifecycle,
588 List<? extends PortletFilter> filters)
589 throws IOException, PortletException {
590
591 FilterChain filterChain = new FilterChainImpl(_portlet, filters);
592
593 if (_portletConfigImpl.isWARFile()) {
594 String invokerPortletName = _portletConfigImpl.getInitParameter(
595 INIT_INVOKER_PORTLET_NAME);
596
597 if (invokerPortletName == null) {
598 invokerPortletName = _portletConfigImpl.getPortletName();
599 }
600
601 String path = StringPool.SLASH + invokerPortletName + "/invoke";
602
603 RequestDispatcher requestDispatcher =
604 _portletContextImpl.getServletContext().getRequestDispatcher(
605 path);
606
607 HttpServletRequest request = portletRequest.getHttpServletRequest();
608 HttpServletResponse response =
609 portletResponse.getHttpServletResponse();
610
611 request.setAttribute(JavaConstants.JAVAX_PORTLET_PORTLET, _portlet);
612 request.setAttribute(PortletRequest.LIFECYCLE_PHASE, lifecycle);
613 request.setAttribute(
614 PortletServlet.PORTLET_SERVLET_FILTER_CHAIN, filterChain);
615
616 try {
617
618
621 if (lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
622 requestDispatcher.forward(request, response);
623 }
624 else {
625 requestDispatcher.include(request, response);
626 }
627 }
628 catch (ServletException se) {
629 Throwable cause = se.getRootCause();
630
631 if (cause instanceof PortletException) {
632 throw (PortletException)cause;
633 }
634
635 throw new PortletException(cause);
636 }
637 }
638 else {
639 PortletFilterUtil.doFilter(
640 portletRequest, portletResponse, lifecycle, filterChain);
641 }
642
643 Map<String, String[]> properties = portletResponse.getProperties();
644
645 if ((properties != null) && (properties.size() > 0)) {
646 if (_expCache != null) {
647 String[] expCache = properties.get(
648 RenderResponse.EXPIRATION_CACHE);
649
650 if ((expCache != null) && (expCache.length > 0) &&
651 (expCache[0] != null)) {
652
653 _expCache = new Integer(GetterUtil.getInteger(expCache[0]));
654 }
655 }
656 }
657 }
658
659 protected void invokeAction(
660 ActionRequest actionRequest, ActionResponse actionResponse)
661 throws IOException, PortletException {
662
663 LiferayPortletRequest portletRequest =
664 (LiferayPortletRequest)actionRequest;
665 LiferayPortletResponse portletResponse =
666 (LiferayPortletResponse)actionResponse;
667
668 String portletId = _getPortletId(portletResponse);
669
670 List<ActionFilter> actionFilters = _actionFiltersMap.get(portletId);
671
672 invoke(
673 portletRequest, portletResponse, PortletRequest.ACTION_PHASE,
674 actionFilters);
675 }
676
677 protected void invokeEvent(
678 EventRequest eventRequest, EventResponse eventResponse)
679 throws IOException, PortletException {
680
681 LiferayPortletRequest portletRequest =
682 (LiferayPortletRequest)eventRequest;
683 LiferayPortletResponse portletResponse =
684 (LiferayPortletResponse)eventResponse;
685
686 String portletId = _getPortletId(portletResponse);
687
688 List<EventFilter> eventFilters = _eventFiltersMap.get(portletId);
689
690 invoke(
691 portletRequest, portletResponse, PortletRequest.EVENT_PHASE,
692 eventFilters);
693 }
694
695 protected String invokeRender(
696 RenderRequest renderRequest, RenderResponse renderResponse)
697 throws IOException, PortletException {
698
699 LiferayPortletRequest portletRequest =
700 (LiferayPortletRequest)renderRequest;
701 LiferayPortletResponse portletResponse =
702 (LiferayPortletResponse)renderResponse;
703
704 String portletId = _getPortletId(portletResponse);
705
706 List<RenderFilter> renderFilters = _renderFiltersMap.get(portletId);
707
708 invoke(
709 portletRequest, portletResponse, PortletRequest.RENDER_PHASE,
710 renderFilters);
711
712 RenderResponseImpl renderResponseImpl =
713 (RenderResponseImpl)renderResponse;
714
715 return renderResponseImpl.getTitle();
716 }
717
718 protected void invokeResource(
719 ResourceRequest resourceRequest, ResourceResponse resourceResponse)
720 throws IOException, PortletException {
721
722 LiferayPortletRequest portletRequest =
723 (LiferayPortletRequest)resourceRequest;
724 LiferayPortletResponse portletResponse =
725 (LiferayPortletResponse)resourceResponse;
726
727 String portletId = _getPortletId(portletResponse);
728
729 List<ResourceFilter> resourceFilters = _resourceFiltersMap.get(
730 portletId);
731
732 invoke(
733 portletRequest, portletResponse, PortletRequest.RESOURCE_PHASE,
734 resourceFilters);
735 }
736
737 protected void removePortletFilters() {
738 _actionFiltersMap.remove(_portletId);
739 _eventFiltersMap.remove(_portletId);
740 _renderFiltersMap.remove(_portletId);
741 _resourceFiltersMap.remove(_portletId);
742 }
743
744 private String _getPortletId(LiferayPortletResponse portletResponse) {
745 PortletResponseImpl portletResponseImpl =
746 (PortletResponseImpl)portletResponse;
747
748 com.liferay.portal.model.Portlet portlet =
749 portletResponseImpl.getPortlet();
750
751 return portlet.getPortletId();
752 }
753
754 private static Log _log = LogFactoryUtil.getLog(InvokerPortletImpl.class);
755
756 private com.liferay.portal.model.Portlet _portletModel;
757 private String _portletId;
758 private Portlet _portlet;
759 private PortletConfigImpl _portletConfigImpl;
760 private PortletContextImpl _portletContextImpl;
761 private Integer _expCache;
762 private boolean _checkAuthToken;
763 private boolean _destroyable;
764 private boolean _facesPortlet;
765 private boolean _strutsPortlet;
766 private boolean _strutsBridgePortlet;
767 private Map<String, List<ActionFilter>> _actionFiltersMap =
768 new HashMap<String, List<ActionFilter>>();
769 private Map<String, List<EventFilter>> _eventFiltersMap =
770 new HashMap<String, List<EventFilter>>();
771 private Map<String, List<RenderFilter>> _renderFiltersMap =
772 new HashMap<String, List<RenderFilter>>();
773 private Map<String, List<ResourceFilter>> _resourceFiltersMap =
774 new HashMap<String, List<ResourceFilter>>();
775
776 }