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