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.LiferayPortletConfig;
021 import com.liferay.portal.kernel.portlet.LiferayPortletContext;
022 import com.liferay.portal.kernel.portlet.LiferayPortletRequest;
023 import com.liferay.portal.kernel.portlet.LiferayPortletResponse;
024 import com.liferay.portal.kernel.portlet.PortletFilterUtil;
025 import com.liferay.portal.kernel.servlet.BufferCacheServletResponse;
026 import com.liferay.portal.kernel.servlet.PluginContextListener;
027 import com.liferay.portal.kernel.servlet.PortletServlet;
028 import com.liferay.portal.kernel.util.ClassUtil;
029 import com.liferay.portal.kernel.util.GetterUtil;
030 import com.liferay.portal.kernel.util.JavaConstants;
031 import com.liferay.portal.kernel.util.StringBundler;
032 import com.liferay.portal.kernel.util.StringPool;
033 import com.liferay.portal.kernel.util.StringUtil;
034 import com.liferay.portal.kernel.util.Time;
035 import com.liferay.portal.model.Layout;
036 import com.liferay.portal.model.PortletApp;
037 import com.liferay.portal.model.PortletConstants;
038 import com.liferay.portal.model.impl.PortletFilterImpl;
039 import com.liferay.portal.tools.deploy.PortletDeployer;
040 import com.liferay.portal.util.ClassLoaderUtil;
041 import com.liferay.portal.util.PropsValues;
042 import com.liferay.portal.util.WebKeys;
043
044 import java.io.IOException;
045 import java.io.PrintWriter;
046
047 import java.util.ArrayList;
048 import java.util.Collections;
049 import java.util.List;
050 import java.util.Map;
051 import java.util.Set;
052 import java.util.concurrent.ConcurrentHashMap;
053
054 import javax.portlet.ActionRequest;
055 import javax.portlet.ActionResponse;
056 import javax.portlet.EventRequest;
057 import javax.portlet.EventResponse;
058 import javax.portlet.Portlet;
059 import javax.portlet.PortletConfig;
060 import javax.portlet.PortletContext;
061 import javax.portlet.PortletException;
062 import javax.portlet.PortletRequest;
063 import javax.portlet.PortletSession;
064 import javax.portlet.RenderRequest;
065 import javax.portlet.RenderResponse;
066 import javax.portlet.ResourceRequest;
067 import javax.portlet.ResourceResponse;
068 import javax.portlet.filter.ActionFilter;
069 import javax.portlet.filter.EventFilter;
070 import javax.portlet.filter.FilterChain;
071 import javax.portlet.filter.PortletFilter;
072 import javax.portlet.filter.RenderFilter;
073 import javax.portlet.filter.ResourceFilter;
074
075 import javax.servlet.RequestDispatcher;
076 import javax.servlet.ServletContext;
077 import javax.servlet.ServletException;
078 import javax.servlet.http.HttpServletRequest;
079 import javax.servlet.http.HttpServletResponse;
080 import javax.servlet.http.HttpSession;
081
082 import org.apache.commons.lang.time.StopWatch;
083
084
089 public class InvokerPortletImpl implements InvokerPortlet {
090
091 public static void clearResponse(
092 HttpSession session, long plid, String portletId, String languageId) {
093
094 String sesResponseId = encodeResponseKey(plid, portletId, languageId);
095
096 getResponses(session).remove(sesResponseId);
097 }
098
099 public static void clearResponses(HttpSession session) {
100 getResponses(session).clear();
101 }
102
103 public static void clearResponses(PortletSession session) {
104 getResponses(session).clear();
105 }
106
107 public static String encodeResponseKey(
108 long plid, String portletId, String languageId) {
109
110 StringBundler sb = new StringBundler(5);
111
112 sb.append(StringUtil.toHexString(plid));
113 sb.append(StringPool.UNDERLINE);
114 sb.append(portletId);
115 sb.append(StringPool.UNDERLINE);
116 sb.append(languageId);
117
118 return sb.toString();
119 }
120
121 public static Map<String, InvokerPortletResponse> getResponses(
122 HttpSession session) {
123
124 Map<String, InvokerPortletResponse> responses =
125 (Map<String, InvokerPortletResponse>)session.getAttribute(
126 WebKeys.CACHE_PORTLET_RESPONSES);
127
128 if (responses == null) {
129 responses = new ConcurrentHashMap<String, InvokerPortletResponse>();
130
131 session.setAttribute(WebKeys.CACHE_PORTLET_RESPONSES, responses);
132 }
133
134 return responses;
135 }
136
137 public static Map<String, InvokerPortletResponse> getResponses(
138 PortletSession portletSession) {
139
140 return getResponses(
141 ((PortletSessionImpl)portletSession).getHttpSession());
142 }
143
144 public InvokerPortletImpl(
145 com.liferay.portal.model.Portlet portletModel, Portlet portlet,
146 PortletConfig portletConfig, PortletContext portletContext,
147 boolean checkAuthToken, boolean facesPortlet, boolean strutsPortlet,
148 boolean strutsBridgePortlet)
149 throws PortletException {
150
151 _initialize(
152 portletModel, portlet, portletConfig, portletContext,
153 checkAuthToken, facesPortlet, strutsPortlet, strutsBridgePortlet);
154 }
155
156 public InvokerPortletImpl(
157 com.liferay.portal.model.Portlet portletModel, Portlet portlet,
158 PortletContext portletContext)
159 throws PortletException {
160
161 Map<String, String> initParams = portletModel.getInitParams();
162
163 boolean checkAuthToken = GetterUtil.getBoolean(
164 initParams.get("check-auth-token"), true);
165
166 boolean facesPortlet = false;
167
168 if (ClassUtil.isSubclass(
169 portlet.getClass(), PortletDeployer.JSF_STANDARD)) {
170
171 facesPortlet = true;
172 }
173
174 boolean strutsPortlet = ClassUtil.isSubclass(
175 portlet.getClass(), StrutsPortlet.class);
176
177 boolean strutsBridgePortlet = ClassUtil.isSubclass(
178 portlet.getClass(),
179 "org.apache.portals.bridges.struts.StrutsPortlet");
180
181 _initialize(
182 portletModel, portlet, null, portletContext, checkAuthToken,
183 facesPortlet, strutsPortlet, strutsBridgePortlet);
184 }
185
186 @Override
187 public void destroy() {
188 if (PortletConstants.hasInstanceId(_portletModel.getPortletId())) {
189 if (_log.isWarnEnabled()) {
190 _log.warn("Destroying an instanced portlet is not allowed");
191 }
192
193 return;
194 }
195
196 ClassLoader contextClassLoader =
197 ClassLoaderUtil.getContextClassLoader();
198
199 ClassLoader portletClassLoader = getPortletClassLoader();
200
201 try {
202 if (portletClassLoader != null) {
203 ClassLoaderUtil.setContextClassLoader(portletClassLoader);
204 }
205
206 removePortletFilters();
207
208 _portlet.destroy();
209 }
210 finally {
211 if (portletClassLoader != null) {
212 ClassLoaderUtil.setContextClassLoader(contextClassLoader);
213 }
214 }
215 }
216
217 @Override
218 public Integer getExpCache() {
219 return _expCache;
220 }
221
222 @Override
223 public Portlet getPortlet() {
224 return _portlet;
225 }
226
227 @Override
228 public ClassLoader getPortletClassLoader() {
229 ClassLoader classLoader =
230 (ClassLoader)_liferayPortletContext.getAttribute(
231 PluginContextListener.PLUGIN_CLASS_LOADER);
232
233 if (classLoader == null) {
234 classLoader = ClassLoaderUtil.getPortalClassLoader();
235 }
236
237 return classLoader;
238 }
239
240 @Override
241 public PortletConfig getPortletConfig() {
242 return _liferayPortletConfig;
243 }
244
245 @Override
246 public PortletContext getPortletContext() {
247 return _liferayPortletContext;
248 }
249
250 @Override
251 public Portlet getPortletInstance() {
252 return _portlet;
253 }
254
255 @Override
256 public void init(PortletConfig portletConfig) throws PortletException {
257 _liferayPortletConfig = (LiferayPortletConfig)portletConfig;
258
259 ClassLoader contextClassLoader =
260 ClassLoaderUtil.getContextClassLoader();
261
262 ClassLoader portletClassLoader = getPortletClassLoader();
263
264 try {
265 if (portletClassLoader != null) {
266 ClassLoaderUtil.setContextClassLoader(portletClassLoader);
267 }
268
269 _portlet.init(portletConfig);
270 }
271 finally {
272 if (portletClassLoader != null) {
273 ClassLoaderUtil.setContextClassLoader(contextClassLoader);
274 }
275 }
276 }
277
278 @Override
279 public boolean isCheckAuthToken() {
280 return _checkAuthToken;
281 }
282
283 @Override
284 public boolean isFacesPortlet() {
285 return _facesPortlet;
286 }
287
288 @Override
289 public boolean isStrutsBridgePortlet() {
290 return _strutsBridgePortlet;
291 }
292
293 @Override
294 public boolean isStrutsPortlet() {
295 return _strutsPortlet;
296 }
297
298 @Override
299 public void processAction(
300 ActionRequest actionRequest, ActionResponse actionResponse)
301 throws IOException {
302
303 StopWatch stopWatch = new StopWatch();
304
305 stopWatch.start();
306
307 try {
308 invokeAction(actionRequest, actionResponse);
309 }
310 catch (PortletException pe) {
311 actionRequest.setAttribute(
312 _portletId + PortletException.class.getName(), pe);
313 }
314
315 if (_log.isDebugEnabled()) {
316 _log.debug(
317 "processAction for " + _portletId + " takes " +
318 stopWatch.getTime() + " ms");
319 }
320 }
321
322 @Override
323 public void processEvent(
324 EventRequest eventRequest, EventResponse eventResponse)
325 throws IOException, PortletException {
326
327 StopWatch stopWatch = new StopWatch();
328
329 stopWatch.start();
330
331 invokeEvent(eventRequest, eventResponse);
332
333 if (_log.isDebugEnabled()) {
334 _log.debug(
335 "processEvent for " + _portletId + " takes " +
336 stopWatch.getTime() + " ms");
337 }
338 }
339
340 @Override
341 public void render(
342 RenderRequest renderRequest, RenderResponse renderResponse)
343 throws IOException, PortletException {
344
345 PortletException portletException =
346 (PortletException)renderRequest.getAttribute(
347 _portletId + PortletException.class.getName());
348
349 if (portletException != null) {
350 throw portletException;
351 }
352
353 StopWatch stopWatch = new StopWatch();
354
355 stopWatch.start();
356
357 String remoteUser = renderRequest.getRemoteUser();
358
359 if ((remoteUser == null) || (_expCache == null) ||
360 (_expCache.intValue() == 0)) {
361
362 invokeRender(renderRequest, renderResponse);
363 }
364 else {
365 RenderResponseImpl renderResponseImpl =
366 (RenderResponseImpl)renderResponse;
367
368 BufferCacheServletResponse bufferCacheServletResponse =
369 (BufferCacheServletResponse)
370 renderResponseImpl.getHttpServletResponse();
371
372 PortletSession portletSession = renderRequest.getPortletSession();
373
374 long now = System.currentTimeMillis();
375
376 Layout layout = (Layout)renderRequest.getAttribute(WebKeys.LAYOUT);
377
378 Map<String, InvokerPortletResponse> sessionResponses = getResponses(
379 portletSession);
380
381 String sessionResponseId = encodeResponseKey(
382 layout.getPlid(), _portletId,
383 LanguageUtil.getLanguageId(renderRequest));
384
385 InvokerPortletResponse response = sessionResponses.get(
386 sessionResponseId);
387
388 if (response == null) {
389 String title = invokeRender(renderRequest, renderResponse);
390
391 response = new InvokerPortletResponse(
392 title, bufferCacheServletResponse.getString(),
393 now + Time.SECOND * _expCache.intValue());
394
395 sessionResponses.put(sessionResponseId, response);
396 }
397 else if ((response.getTime() < now) && (_expCache.intValue() > 0)) {
398 String title = invokeRender(renderRequest, renderResponse);
399
400 response.setTitle(title);
401 response.setContent(bufferCacheServletResponse.getString());
402 response.setTime(now + Time.SECOND * _expCache.intValue());
403 }
404 else {
405 renderResponseImpl.setTitle(response.getTitle());
406
407 PrintWriter printWriter =
408 bufferCacheServletResponse.getWriter();
409
410 printWriter.print(response.getContent());
411 }
412 }
413
414 Map<String, String[]> properties =
415 ((RenderResponseImpl)renderResponse).getProperties();
416
417 if (properties.containsKey("clear-request-parameters")) {
418 Map<String, String[]> renderParameters =
419 ((RenderRequestImpl)renderRequest).getRenderParameters();
420
421 renderParameters.clear();
422 }
423
424 if (_log.isDebugEnabled()) {
425 _log.debug(
426 "render for " + _portletId + " takes " + stopWatch.getTime() +
427 " ms");
428 }
429 }
430
431 @Override
432 public void serveResource(
433 ResourceRequest resourceRequest, ResourceResponse resourceResponse)
434 throws IOException {
435
436 StopWatch stopWatch = new StopWatch();
437
438 stopWatch.start();
439
440 try {
441 invokeResource(resourceRequest, resourceResponse);
442 }
443 catch (PortletException pe) {
444 resourceRequest.setAttribute(
445 _portletId + PortletException.class.getName(), pe);
446 }
447
448 if (_log.isDebugEnabled()) {
449 _log.debug(
450 "serveResource for " + _portletId + " takes " +
451 stopWatch.getTime() + " ms");
452 }
453 }
454
455 @Override
456 public void setPortletFilters() throws PortletException {
457 PortletApp portletApp = _portletModel.getPortletApp();
458
459 PortletContextBag portletContextBag = PortletContextBagPool.get(
460 portletApp.getServletContextName());
461
462 if (portletApp.isWARFile() && (portletContextBag == null)) {
463 return;
464 }
465
466 removePortletFilters();
467
468 Map<String, com.liferay.portal.model.PortletFilter> portletFilters =
469 _portletModel.getPortletFilters();
470
471 for (Map.Entry<String, com.liferay.portal.model.PortletFilter> entry :
472 portletFilters.entrySet()) {
473
474 com.liferay.portal.model.PortletFilter portletFilterModel =
475 entry.getValue();
476
477 PortletFilter portletFilter = PortletFilterFactory.create(
478 portletFilterModel, _liferayPortletContext);
479
480 Set<String> lifecycles = portletFilterModel.getLifecycles();
481
482 if (lifecycles.contains(PortletRequest.ACTION_PHASE)) {
483 _actionFilters.add((ActionFilter)portletFilter);
484 }
485
486 if (lifecycles.contains(PortletRequest.EVENT_PHASE)) {
487 _eventFilters.add((EventFilter)portletFilter);
488 }
489
490 if (lifecycles.contains(PortletRequest.RENDER_PHASE)) {
491 _renderFilters.add((RenderFilter)portletFilter);
492 }
493
494 if (lifecycles.contains(PortletRequest.RESOURCE_PHASE)) {
495 _resourceFilters.add((ResourceFilter)portletFilter);
496 }
497 }
498
499 ClassLoader classLoader = ClassLoaderUtil.getContextClassLoader();
500
501 try {
502 ClassLoaderUtil.setContextClassLoader(
503 ClassLoaderUtil.getPortalClassLoader());
504
505 for (String portletFilterClassName :
506 PropsValues.PORTLET_FILTERS_SYSTEM) {
507
508 com.liferay.portal.model.PortletFilter portletFilterModel =
509 new PortletFilterImpl(
510 portletFilterClassName, portletFilterClassName,
511 Collections.<String>emptySet(),
512 Collections.<String, String>emptyMap(), portletApp);
513
514 PortletFilter portletFilter = PortletFilterFactory.create(
515 portletFilterModel, _liferayPortletContext);
516
517 _systemPortletFilters.add(portletFilter);
518
519 if (portletFilter instanceof ActionFilter) {
520 _actionFilters.add((ActionFilter)portletFilter);
521 }
522
523 if (portletFilter instanceof EventFilter) {
524 _eventFilters.add((EventFilter)portletFilter);
525 }
526
527 if (portletFilter instanceof RenderFilter) {
528 _renderFilters.add((RenderFilter)portletFilter);
529 }
530
531 if (portletFilter instanceof ResourceFilter) {
532 _resourceFilters.add((ResourceFilter)portletFilter);
533 }
534 }
535 }
536 finally {
537 ClassLoaderUtil.setContextClassLoader(classLoader);
538 }
539 }
540
541 protected void invoke(
542 LiferayPortletRequest portletRequest,
543 LiferayPortletResponse portletResponse, String lifecycle,
544 List<? extends PortletFilter> filters)
545 throws IOException, PortletException {
546
547 FilterChain filterChain = new FilterChainImpl(_portlet, filters);
548
549 if (_liferayPortletConfig.isWARFile()) {
550 String invokerPortletName = _liferayPortletConfig.getInitParameter(
551 INIT_INVOKER_PORTLET_NAME);
552
553 if (invokerPortletName == null) {
554 invokerPortletName = _liferayPortletConfig.getPortletName();
555 }
556
557 String path = StringPool.SLASH + invokerPortletName + "/invoke";
558
559 ServletContext servletContext =
560 _liferayPortletContext.getServletContext();
561
562 RequestDispatcher requestDispatcher =
563 servletContext.getRequestDispatcher(path);
564
565 HttpServletRequest request = portletRequest.getHttpServletRequest();
566 HttpServletResponse response =
567 portletResponse.getHttpServletResponse();
568
569 request.setAttribute(JavaConstants.JAVAX_PORTLET_PORTLET, _portlet);
570 request.setAttribute(PortletRequest.LIFECYCLE_PHASE, lifecycle);
571 request.setAttribute(
572 PortletServlet.PORTLET_SERVLET_FILTER_CHAIN, filterChain);
573
574 try {
575
576
577
578
579 if (lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
580 requestDispatcher.forward(request, response);
581 }
582 else {
583 requestDispatcher.include(request, response);
584 }
585 }
586 catch (ServletException se) {
587 Throwable cause = se.getRootCause();
588
589 if (cause instanceof PortletException) {
590 throw (PortletException)cause;
591 }
592
593 throw new PortletException(cause);
594 }
595 }
596 else {
597 PortletFilterUtil.doFilter(
598 portletRequest, portletResponse, lifecycle, filterChain);
599 }
600
601 portletResponse.transferMarkupHeadElements();
602
603 Map<String, String[]> properties = portletResponse.getProperties();
604
605 if ((properties != null) && (properties.size() > 0)) {
606 if (_expCache != null) {
607 String[] expCache = properties.get(
608 RenderResponse.EXPIRATION_CACHE);
609
610 if ((expCache != null) && (expCache.length > 0) &&
611 (expCache[0] != null)) {
612
613 _expCache = new Integer(GetterUtil.getInteger(expCache[0]));
614 }
615 }
616 }
617 }
618
619 protected void invokeAction(
620 ActionRequest actionRequest, ActionResponse actionResponse)
621 throws IOException, PortletException {
622
623 LiferayPortletRequest portletRequest =
624 (LiferayPortletRequest)actionRequest;
625 LiferayPortletResponse portletResponse =
626 (LiferayPortletResponse)actionResponse;
627
628 invoke(
629 portletRequest, portletResponse, PortletRequest.ACTION_PHASE,
630 _actionFilters);
631 }
632
633 protected void invokeEvent(
634 EventRequest eventRequest, EventResponse eventResponse)
635 throws IOException, PortletException {
636
637 LiferayPortletRequest portletRequest =
638 (LiferayPortletRequest)eventRequest;
639 LiferayPortletResponse portletResponse =
640 (LiferayPortletResponse)eventResponse;
641
642 invoke(
643 portletRequest, portletResponse, PortletRequest.EVENT_PHASE,
644 _eventFilters);
645 }
646
647 protected String invokeRender(
648 RenderRequest renderRequest, RenderResponse renderResponse)
649 throws IOException, PortletException {
650
651 LiferayPortletRequest portletRequest =
652 (LiferayPortletRequest)renderRequest;
653 LiferayPortletResponse portletResponse =
654 (LiferayPortletResponse)renderResponse;
655
656 invoke(
657 portletRequest, portletResponse, PortletRequest.RENDER_PHASE,
658 _renderFilters);
659
660 RenderResponseImpl renderResponseImpl =
661 (RenderResponseImpl)renderResponse;
662
663 return renderResponseImpl.getTitle();
664 }
665
666 protected void invokeResource(
667 ResourceRequest resourceRequest, ResourceResponse resourceResponse)
668 throws IOException, PortletException {
669
670 LiferayPortletRequest portletRequest =
671 (LiferayPortletRequest)resourceRequest;
672 LiferayPortletResponse portletResponse =
673 (LiferayPortletResponse)resourceResponse;
674
675 invoke(
676 portletRequest, portletResponse, PortletRequest.RESOURCE_PHASE,
677 _resourceFilters);
678 }
679
680 protected void removePortletFilters() {
681 _actionFilters.clear();
682 _eventFilters.clear();
683 _renderFilters.clear();
684 _resourceFilters.clear();
685
686 for (PortletFilter portletFilter : _systemPortletFilters) {
687 portletFilter.destroy();
688 }
689
690 _systemPortletFilters.clear();
691 }
692
693 private void _initialize(
694 com.liferay.portal.model.Portlet portletModel, Portlet portlet,
695 PortletConfig portletConfig, PortletContext portletContext,
696 boolean checkAuthToken, boolean facesPortlet, boolean strutsPortlet,
697 boolean strutsBridgePortlet)
698 throws PortletException {
699
700 _portletModel = portletModel;
701 _portlet = portlet;
702 _liferayPortletConfig = (LiferayPortletConfig)portletConfig;
703 _portletId = _portletModel.getPortletId();
704 _liferayPortletContext = (LiferayPortletContext)portletContext;
705 _checkAuthToken = checkAuthToken;
706 _facesPortlet = facesPortlet;
707 _strutsPortlet = strutsPortlet;
708 _strutsBridgePortlet = strutsBridgePortlet;
709 _expCache = portletModel.getExpCache();
710 setPortletFilters();
711
712 if (_log.isDebugEnabled()) {
713 _log.debug(
714 "Create instance cache wrapper for " +
715 _liferayPortletContext.getPortlet().getPortletId());
716 }
717 }
718
719 private static Log _log = LogFactoryUtil.getLog(InvokerPortletImpl.class);
720
721 private List<ActionFilter> _actionFilters = new ArrayList<ActionFilter>();
722 private boolean _checkAuthToken;
723 private List<EventFilter> _eventFilters = new ArrayList<EventFilter>();
724 private Integer _expCache;
725 private boolean _facesPortlet;
726 private LiferayPortletConfig _liferayPortletConfig;
727 private LiferayPortletContext _liferayPortletContext;
728 private Portlet _portlet;
729 private String _portletId;
730 private com.liferay.portal.model.Portlet _portletModel;
731 private List<RenderFilter> _renderFilters = new ArrayList<RenderFilter>();
732 private List<ResourceFilter> _resourceFilters =
733 new ArrayList<ResourceFilter>();
734 private boolean _strutsBridgePortlet;
735 private boolean _strutsPortlet;
736 private List<PortletFilter> _systemPortletFilters =
737 new ArrayList<PortletFilter>();
738
739 }