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