001
014
015 package com.liferay.portlet;
016
017 import com.liferay.portal.kernel.language.LanguageUtil;
018 import com.liferay.portal.kernel.log.Log;
019 import com.liferay.portal.kernel.log.LogFactoryUtil;
020 import com.liferay.portal.kernel.portlet.LiferayPortletRequest;
021 import com.liferay.portal.kernel.portlet.LiferayPortletResponse;
022 import com.liferay.portal.kernel.portlet.PortletFilterUtil;
023 import com.liferay.portal.kernel.servlet.PortletServlet;
024 import com.liferay.portal.kernel.servlet.StringServletResponse;
025 import com.liferay.portal.kernel.util.ClassUtil;
026 import com.liferay.portal.kernel.util.GetterUtil;
027 import com.liferay.portal.kernel.util.JavaConstants;
028 import com.liferay.portal.kernel.util.StringBundler;
029 import com.liferay.portal.kernel.util.StringPool;
030 import com.liferay.portal.kernel.util.Time;
031 import com.liferay.portal.model.Layout;
032 import com.liferay.portal.tools.deploy.PortletDeployer;
033 import com.liferay.portal.util.WebKeys;
034
035 import java.io.IOException;
036
037 import java.util.ArrayList;
038 import java.util.HashMap;
039 import java.util.List;
040 import java.util.Map;
041 import java.util.Set;
042 import java.util.concurrent.ConcurrentHashMap;
043
044 import javax.portlet.ActionRequest;
045 import javax.portlet.ActionResponse;
046 import javax.portlet.EventRequest;
047 import javax.portlet.EventResponse;
048 import javax.portlet.Portlet;
049 import javax.portlet.PortletConfig;
050 import javax.portlet.PortletContext;
051 import javax.portlet.PortletException;
052 import javax.portlet.PortletRequest;
053 import javax.portlet.PortletSession;
054 import javax.portlet.RenderRequest;
055 import javax.portlet.RenderResponse;
056 import javax.portlet.ResourceRequest;
057 import javax.portlet.ResourceResponse;
058 import javax.portlet.filter.ActionFilter;
059 import javax.portlet.filter.EventFilter;
060 import javax.portlet.filter.FilterChain;
061 import javax.portlet.filter.PortletFilter;
062 import javax.portlet.filter.RenderFilter;
063 import javax.portlet.filter.ResourceFilter;
064
065 import javax.servlet.RequestDispatcher;
066 import javax.servlet.ServletException;
067 import javax.servlet.http.HttpServletRequest;
068 import javax.servlet.http.HttpServletResponse;
069 import javax.servlet.http.HttpSession;
070
071 import org.apache.commons.lang.time.StopWatch;
072
073
077 public class InvokerPortletImpl implements InvokerPortlet {
078
079 public static void clearResponse(
080 HttpSession session, long plid, String portletId, String languageId) {
081
082 String sesResponseId = encodeResponseKey(plid, portletId, languageId);
083
084 getResponses(session).remove(sesResponseId);
085 }
086
087 public static void clearResponses(HttpSession session) {
088 getResponses(session).clear();
089 }
090
091 public static void clearResponses(PortletSession session) {
092 getResponses(session).clear();
093 }
094
095 public static String encodeResponseKey(
096 long plid, String portletId, String languageId) {
097
098 StringBundler sb = new StringBundler(5);
099
100 sb.append(plid);
101 sb.append(StringPool.UNDERLINE);
102 sb.append(portletId);
103 sb.append(StringPool.UNDERLINE);
104 sb.append(languageId);
105
106 return sb.toString();
107 }
108
109 public static Map<String, InvokerPortletResponse> getResponses(
110 HttpSession session) {
111
112 Map<String, InvokerPortletResponse> responses =
113 (Map<String, InvokerPortletResponse>)session.getAttribute(
114 WebKeys.CACHE_PORTLET_RESPONSES);
115
116 if (responses == null) {
117 responses = new ConcurrentHashMap<String, InvokerPortletResponse>();
118
119 session.setAttribute(WebKeys.CACHE_PORTLET_RESPONSES, responses);
120 }
121
122 return responses;
123 }
124
125 public static Map<String, InvokerPortletResponse> getResponses(
126 PortletSession portletSession) {
127
128 return getResponses(
129 ((PortletSessionImpl)portletSession).getHttpSession());
130 }
131
132 public InvokerPortlet create(
133 com.liferay.portal.model.Portlet portletModel, Portlet portlet,
134 PortletContext portletContext)
135 throws PortletException {
136
137 try {
138 InvokerPortlet invokerPortlet = (InvokerPortlet)clone();
139
140 invokerPortlet.prepare(portletModel, portlet, portletContext);
141
142 return invokerPortlet;
143 }
144 catch (PortletException pe) {
145 throw pe;
146 }
147 catch (Exception e) {
148 throw new PortletException(e);
149 }
150 }
151
152 public InvokerPortlet create(
153 com.liferay.portal.model.Portlet portletModel, Portlet portlet,
154 PortletConfig portletConfig, PortletContext portletContext,
155 boolean checkAuthToken, boolean facesPortlet, boolean strutsPortlet,
156 boolean strutsBridgePortlet)
157 throws PortletException {
158
159 try {
160 InvokerPortlet invokerPortlet = (InvokerPortlet)clone();
161
162 invokerPortlet.prepare(
163 portletModel, portlet, portletConfig, portletContext,
164 checkAuthToken, facesPortlet, strutsPortlet,
165 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 isCheckAuthToken() {
256 return _checkAuthToken;
257 }
258
259 public boolean isDestroyable() {
260 return _destroyable;
261 }
262
263 public boolean isFacesPortlet() {
264 return _facesPortlet;
265 }
266
267 public boolean isStrutsBridgePortlet() {
268 return _strutsBridgePortlet;
269 }
270
271 public boolean isStrutsPortlet() {
272 return _strutsPortlet;
273 }
274
275 public void prepare(
276 com.liferay.portal.model.Portlet portletModel, Portlet portlet,
277 PortletContext portletContext)
278 throws PortletException {
279
280 _portletModel = portletModel;
281 _portletId = _portletModel.getPortletId();
282 _portlet = portlet;
283 _portletContextImpl = (PortletContextImpl)portletContext;
284
285 if (_log.isDebugEnabled()) {
286 _log.debug(
287 "Create root cache wrapper for " +
288 _portletContextImpl.getPortlet().getPortletId());
289 }
290
291 Map<String, String> initParams = portletModel.getInitParams();
292
293 _checkAuthToken = GetterUtil.getBoolean(
294 initParams.get("check-auth-token"), true);
295
296 if (ClassUtil.isSubclass(
297 _portlet.getClass(), PortletDeployer.JSF_MYFACES) ||
298 ClassUtil.isSubclass(
299 _portlet.getClass(), PortletDeployer.JSF_STANDARD) ||
300 ClassUtil.isSubclass(
301 _portlet.getClass(), PortletDeployer.JSF_SUN)) {
302
303 _facesPortlet = true;
304 }
305
306 _strutsPortlet = ClassUtil.isSubclass(
307 portlet.getClass(), StrutsPortlet.class);
308 _strutsBridgePortlet = ClassUtil.isSubclass(
309 portlet.getClass(),
310 "org.apache.portals.bridges.struts.StrutsPortlet");
311 _expCache = portletModel.getExpCache();
312 setPortletFilters();
313 }
314
315 public void prepare(
316 com.liferay.portal.model.Portlet portletModel, Portlet portlet,
317 PortletConfig portletConfig, PortletContext portletContext,
318 boolean checkAuthToken, boolean facesPortlet, boolean strutsPortlet,
319 boolean strutsBridgePortlet)
320 throws PortletException {
321
322
323
324 _portletModel = portletModel;
325 _portlet = portlet;
326 _portletId = _portletModel.getPortletId();
327 _portletContextImpl = (PortletContextImpl)portletContext;
328 _checkAuthToken = checkAuthToken;
329 _facesPortlet = facesPortlet;
330 _strutsPortlet = strutsPortlet;
331 _strutsBridgePortlet = strutsBridgePortlet;
332 _expCache = portletModel.getExpCache();
333 setPortletFilters();
334
335 if (_log.isDebugEnabled()) {
336 _log.debug(
337 "Create instance cache wrapper for " +
338 _portletContextImpl.getPortlet().getPortletId());
339 }
340
341
342
343 _portletConfigImpl = (PortletConfigImpl)portletConfig;
344 }
345
346 public void processAction(
347 ActionRequest actionRequest, ActionResponse actionResponse)
348 throws IOException {
349
350 StopWatch stopWatch = null;
351
352 if (_log.isDebugEnabled()) {
353 stopWatch = new StopWatch();
354
355 stopWatch.start();
356 }
357
358 try {
359 invokeAction(actionRequest, actionResponse);
360 }
361 catch (PortletException pe) {
362 actionRequest.setAttribute(
363 _portletId + PortletException.class.getName(), pe);
364 }
365
366 if (_log.isDebugEnabled()) {
367 if (stopWatch != null) {
368 _log.debug(
369 "processAction for " + _portletId + " takes " +
370 stopWatch.getTime() + " ms");
371 }
372 else {
373 _log.debug("processAction for " + _portletId + " is finished");
374 }
375 }
376 }
377
378 public void processEvent(
379 EventRequest eventRequest, EventResponse eventResponse)
380 throws IOException, PortletException {
381
382 StopWatch stopWatch = null;
383
384 if (_log.isDebugEnabled()) {
385 stopWatch = new StopWatch();
386
387 stopWatch.start();
388 }
389
390 invokeEvent(eventRequest, eventResponse);
391
392 if (_log.isDebugEnabled()) {
393 _log.debug(
394 "processEvent for " + _portletId + " takes " +
395 stopWatch.getTime() + " ms");
396 }
397 }
398
399 public void render(
400 RenderRequest renderRequest, RenderResponse renderResponse)
401 throws IOException, PortletException {
402
403 PortletException portletException =
404 (PortletException)renderRequest.getAttribute(
405 _portletId + PortletException.class.getName());
406
407 if (portletException != null) {
408 throw portletException;
409 }
410
411 StopWatch stopWatch = null;
412
413 if (_log.isDebugEnabled()) {
414 stopWatch = new StopWatch();
415
416 stopWatch.start();
417 }
418
419 String remoteUser = renderRequest.getRemoteUser();
420
421 if ((remoteUser == null) || (_expCache == null) ||
422 (_expCache.intValue() == 0)) {
423
424 invokeRender(renderRequest, renderResponse);
425 }
426 else {
427 RenderResponseImpl renderResponseImpl =
428 (RenderResponseImpl)renderResponse;
429
430 StringServletResponse stringResponse = (StringServletResponse)
431 renderResponseImpl.getHttpServletResponse();
432
433 PortletSession portletSession = renderRequest.getPortletSession();
434
435 long now = System.currentTimeMillis();
436
437 Layout layout = (Layout)renderRequest.getAttribute(WebKeys.LAYOUT);
438
439 Map<String, InvokerPortletResponse> sessionResponses =
440 getResponses(portletSession);
441
442 String sessionResponseId = encodeResponseKey(
443 layout.getPlid(), _portletId,
444 LanguageUtil.getLanguageId(renderRequest));
445
446 InvokerPortletResponse response = sessionResponses.get(
447 sessionResponseId);
448
449 if (response == null) {
450 String title = invokeRender(renderRequest, renderResponse);
451
452 response = new InvokerPortletResponse(
453 title, stringResponse.getString(),
454 now + Time.SECOND * _expCache.intValue());
455
456 sessionResponses.put(sessionResponseId, response);
457 }
458 else if ((response.getTime() < now) &&
459 (_expCache.intValue() > 0)) {
460
461 String title = invokeRender(renderRequest, renderResponse);
462
463 response.setTitle(title);
464 response.setContent(stringResponse.getString());
465 response.setTime(now + Time.SECOND * _expCache.intValue());
466 }
467 else {
468 renderResponseImpl.setTitle(response.getTitle());
469 stringResponse.getWriter().print(response.getContent());
470 }
471 }
472
473 Map<String, String[]> properties =
474 ((RenderResponseImpl)renderResponse).getProperties();
475
476 if (properties.containsKey("clear-request-parameters")) {
477 Map<String, String[]> renderParameters =
478 ((RenderRequestImpl)renderRequest).getRenderParameters();
479
480 renderParameters.clear();
481 }
482
483 if (_log.isDebugEnabled()) {
484 _log.debug(
485 "render for " + _portletId + " takes " + stopWatch.getTime() +
486 " ms");
487 }
488 }
489
490 public void serveResource(
491 ResourceRequest resourceRequest, ResourceResponse resourceResponse)
492 throws IOException {
493
494 StopWatch stopWatch = null;
495
496 if (_log.isDebugEnabled()) {
497 stopWatch = new StopWatch();
498
499 stopWatch.start();
500 }
501
502 try {
503 invokeResource(resourceRequest, resourceResponse);
504 }
505 catch (PortletException pe) {
506 resourceRequest.setAttribute(
507 _portletId + PortletException.class.getName(), pe);
508 }
509
510 if (_log.isDebugEnabled()) {
511 _log.debug(
512 "serveResource for " + _portletId + " takes " +
513 stopWatch.getTime() + " ms");
514 }
515 }
516
517 public void setPortletFilters() throws PortletException {
518 removePortletFilters();
519
520 Map<String, com.liferay.portal.model.PortletFilter> portletFilters =
521 _portletModel.getPortletFilters();
522
523 for (Map.Entry<String, com.liferay.portal.model.PortletFilter> entry :
524 portletFilters.entrySet()) {
525
526 com.liferay.portal.model.PortletFilter portletFilterModel =
527 entry.getValue();
528
529 PortletFilter portletFilter = PortletFilterFactory.create(
530 portletFilterModel, _portletContextImpl);
531
532 Set<String> lifecycles = portletFilterModel.getLifecycles();
533
534 if (lifecycles.contains(PortletRequest.ACTION_PHASE)) {
535 List<ActionFilter> actionFilters = _actionFiltersMap.get(
536 _portletId);
537
538 if (actionFilters == null) {
539 actionFilters = new ArrayList<ActionFilter>();
540 }
541
542 actionFilters.add((ActionFilter)portletFilter);
543
544 _actionFiltersMap.put(_portletId, actionFilters);
545 }
546
547 if (lifecycles.contains(PortletRequest.EVENT_PHASE)) {
548 List<EventFilter> eventFilters = _eventFiltersMap.get(
549 _portletId);
550
551 if (eventFilters == null) {
552 eventFilters = new ArrayList<EventFilter>();
553 }
554
555 eventFilters.add((EventFilter)portletFilter);
556
557 _eventFiltersMap.put(_portletId, eventFilters);
558 }
559
560 if (lifecycles.contains(PortletRequest.RENDER_PHASE)) {
561 List<RenderFilter> renderFilters = _renderFiltersMap.get(
562 _portletId);
563
564 if (renderFilters == null) {
565 renderFilters = new ArrayList<RenderFilter>();
566 }
567
568 renderFilters.add((RenderFilter)portletFilter);
569
570 _renderFiltersMap.put(_portletId, renderFilters);
571 }
572
573 if (lifecycles.contains(PortletRequest.RESOURCE_PHASE)) {
574 List<ResourceFilter> resourceFilters = _resourceFiltersMap.get(
575 _portletId);
576
577 if (resourceFilters == null) {
578 resourceFilters = new ArrayList<ResourceFilter>();
579 }
580
581 resourceFilters.add((ResourceFilter)portletFilter);
582
583 _resourceFiltersMap.put(_portletId, resourceFilters);
584 }
585 }
586 }
587
588 protected void invoke(
589 LiferayPortletRequest portletRequest,
590 LiferayPortletResponse portletResponse, String lifecycle,
591 List<? extends PortletFilter> filters)
592 throws IOException, PortletException {
593
594 FilterChain filterChain = new FilterChainImpl(_portlet, filters);
595
596 if (_portletConfigImpl.isWARFile()) {
597 String invokerPortletName = _portletConfigImpl.getInitParameter(
598 INIT_INVOKER_PORTLET_NAME);
599
600 if (invokerPortletName == null) {
601 invokerPortletName = _portletConfigImpl.getPortletName();
602 }
603
604 String path = StringPool.SLASH + invokerPortletName + "/invoke";
605
606 RequestDispatcher requestDispatcher =
607 _portletContextImpl.getServletContext().getRequestDispatcher(
608 path);
609
610 HttpServletRequest request = portletRequest.getHttpServletRequest();
611 HttpServletResponse response =
612 portletResponse.getHttpServletResponse();
613
614 request.setAttribute(JavaConstants.JAVAX_PORTLET_PORTLET, _portlet);
615 request.setAttribute(PortletRequest.LIFECYCLE_PHASE, lifecycle);
616 request.setAttribute(
617 PortletServlet.PORTLET_SERVLET_FILTER_CHAIN, filterChain);
618
619 try {
620
621
622
623
624 if (lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
625 requestDispatcher.forward(request, response);
626 }
627 else {
628 requestDispatcher.include(request, response);
629 }
630 }
631 catch (ServletException se) {
632 Throwable cause = se.getRootCause();
633
634 if (cause instanceof PortletException) {
635 throw (PortletException)cause;
636 }
637
638 throw new PortletException(cause);
639 }
640 }
641 else {
642 PortletFilterUtil.doFilter(
643 portletRequest, portletResponse, lifecycle, filterChain);
644 }
645
646 portletResponse.transferMarkupHeadElements();
647
648 Map<String, String[]> properties = portletResponse.getProperties();
649
650 if ((properties != null) && (properties.size() > 0)) {
651 if (_expCache != null) {
652 String[] expCache = properties.get(
653 RenderResponse.EXPIRATION_CACHE);
654
655 if ((expCache != null) && (expCache.length > 0) &&
656 (expCache[0] != null)) {
657
658 _expCache = new Integer(GetterUtil.getInteger(expCache[0]));
659 }
660 }
661 }
662 }
663
664 protected void invokeAction(
665 ActionRequest actionRequest, ActionResponse actionResponse)
666 throws IOException, PortletException {
667
668 LiferayPortletRequest portletRequest =
669 (LiferayPortletRequest)actionRequest;
670 LiferayPortletResponse portletResponse =
671 (LiferayPortletResponse)actionResponse;
672
673 String portletId = _getPortletId(portletResponse);
674
675 List<ActionFilter> actionFilters = _actionFiltersMap.get(portletId);
676
677 invoke(
678 portletRequest, portletResponse, PortletRequest.ACTION_PHASE,
679 actionFilters);
680 }
681
682 protected void invokeEvent(
683 EventRequest eventRequest, EventResponse eventResponse)
684 throws IOException, PortletException {
685
686 LiferayPortletRequest portletRequest =
687 (LiferayPortletRequest)eventRequest;
688 LiferayPortletResponse portletResponse =
689 (LiferayPortletResponse)eventResponse;
690
691 String portletId = _getPortletId(portletResponse);
692
693 List<EventFilter> eventFilters = _eventFiltersMap.get(portletId);
694
695 invoke(
696 portletRequest, portletResponse, PortletRequest.EVENT_PHASE,
697 eventFilters);
698 }
699
700 protected String invokeRender(
701 RenderRequest renderRequest, RenderResponse renderResponse)
702 throws IOException, PortletException {
703
704 LiferayPortletRequest portletRequest =
705 (LiferayPortletRequest)renderRequest;
706 LiferayPortletResponse portletResponse =
707 (LiferayPortletResponse)renderResponse;
708
709 String portletId = _getPortletId(portletResponse);
710
711 List<RenderFilter> renderFilters = _renderFiltersMap.get(portletId);
712
713 invoke(
714 portletRequest, portletResponse, PortletRequest.RENDER_PHASE,
715 renderFilters);
716
717 RenderResponseImpl renderResponseImpl =
718 (RenderResponseImpl)renderResponse;
719
720 return renderResponseImpl.getTitle();
721 }
722
723 protected void invokeResource(
724 ResourceRequest resourceRequest, ResourceResponse resourceResponse)
725 throws IOException, PortletException {
726
727 LiferayPortletRequest portletRequest =
728 (LiferayPortletRequest)resourceRequest;
729 LiferayPortletResponse portletResponse =
730 (LiferayPortletResponse)resourceResponse;
731
732 String portletId = _getPortletId(portletResponse);
733
734 List<ResourceFilter> resourceFilters = _resourceFiltersMap.get(
735 portletId);
736
737 invoke(
738 portletRequest, portletResponse, PortletRequest.RESOURCE_PHASE,
739 resourceFilters);
740 }
741
742 protected void removePortletFilters() {
743 _actionFiltersMap.remove(_portletId);
744 _eventFiltersMap.remove(_portletId);
745 _renderFiltersMap.remove(_portletId);
746 _resourceFiltersMap.remove(_portletId);
747 }
748
749 private String _getPortletId(LiferayPortletResponse portletResponse) {
750 PortletResponseImpl portletResponseImpl =
751 (PortletResponseImpl)portletResponse;
752
753 com.liferay.portal.model.Portlet portlet =
754 portletResponseImpl.getPortlet();
755
756 return portlet.getPortletId();
757 }
758
759 private static Log _log = LogFactoryUtil.getLog(InvokerPortletImpl.class);
760
761 private com.liferay.portal.model.Portlet _portletModel;
762 private String _portletId;
763 private Portlet _portlet;
764 private PortletConfigImpl _portletConfigImpl;
765 private PortletContextImpl _portletContextImpl;
766 private Integer _expCache;
767 private boolean _checkAuthToken;
768 private boolean _destroyable;
769 private boolean _facesPortlet;
770 private boolean _strutsPortlet;
771 private boolean _strutsBridgePortlet;
772 private Map<String, List<ActionFilter>> _actionFiltersMap =
773 new HashMap<String, List<ActionFilter>>();
774 private Map<String, List<EventFilter>> _eventFiltersMap =
775 new HashMap<String, List<EventFilter>>();
776 private Map<String, List<RenderFilter>> _renderFiltersMap =
777 new HashMap<String, List<RenderFilter>>();
778 private Map<String, List<ResourceFilter>> _resourceFiltersMap =
779 new HashMap<String, List<ResourceFilter>>();
780
781 }