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