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