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