1
22
23 package com.liferay.portlet;
24
25 import com.liferay.portal.kernel.language.LanguageUtil;
26 import com.liferay.portal.kernel.portlet.LiferayPortletRequest;
27 import com.liferay.portal.kernel.portlet.LiferayPortletResponse;
28 import com.liferay.portal.kernel.portlet.PortletFilterUtil;
29 import com.liferay.portal.kernel.servlet.PortletServlet;
30 import com.liferay.portal.kernel.servlet.StringServletResponse;
31 import com.liferay.portal.kernel.util.ClassUtil;
32 import com.liferay.portal.kernel.util.GetterUtil;
33 import com.liferay.portal.kernel.util.JavaConstants;
34 import com.liferay.portal.kernel.util.StringPool;
35 import com.liferay.portal.kernel.util.Time;
36 import com.liferay.portal.model.Layout;
37 import com.liferay.portal.tools.PortletDeployer;
38 import com.liferay.portal.util.WebKeys;
39
40 import com.sun.portal.portletcontainer.appengine.filter.FilterChainImpl;
41
42 import java.io.IOException;
43
44 import java.util.ArrayList;
45 import java.util.HashMap;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Set;
49
50 import javax.portlet.ActionRequest;
51 import javax.portlet.ActionResponse;
52 import javax.portlet.EventPortlet;
53 import javax.portlet.EventRequest;
54 import javax.portlet.EventResponse;
55 import javax.portlet.Portlet;
56 import javax.portlet.PortletConfig;
57 import javax.portlet.PortletContext;
58 import javax.portlet.PortletException;
59 import javax.portlet.PortletRequest;
60 import javax.portlet.PortletSession;
61 import javax.portlet.RenderRequest;
62 import javax.portlet.RenderResponse;
63 import javax.portlet.ResourceRequest;
64 import javax.portlet.ResourceResponse;
65 import javax.portlet.ResourceServingPortlet;
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 import org.apache.commons.logging.Log;
81 import org.apache.commons.logging.LogFactory;
82
83
90 public class InvokerPortlet
91 implements EventPortlet, Portlet, ResourceServingPortlet {
92
93 public static void clearResponse(
94 HttpSession session, long plid, String portletId, String languageId) {
95
96 String sesResponseId = encodeResponseKey(plid, portletId, languageId);
97
98 getResponses(session).remove(sesResponseId);
99 }
100
101 public static void clearResponses(HttpSession session) {
102 getResponses(session).clear();
103 }
104
105 public static void clearResponses(PortletSession session) {
106 getResponses(session).clear();
107 }
108
109 public static String encodeResponseKey(
110 long plid, String portletId, String languageId) {
111
112 StringBuilder sb = new StringBuilder();
113
114 sb.append(plid);
115 sb.append(StringPool.UNDERLINE);
116 sb.append(portletId);
117 sb.append(StringPool.UNDERLINE);
118 sb.append(languageId);
119
120 return sb.toString();
121 }
122
123 public static Map<String, InvokerPortletResponse> getResponses(
124 HttpSession session) {
125
126 Map<String, InvokerPortletResponse> responses =
127 (Map<String, InvokerPortletResponse>)session.getAttribute(
128 WebKeys.CACHE_PORTLET_RESPONSES);
129
130 if (responses == null) {
131 responses = new HashMap<String, InvokerPortletResponse>();
132
133 session.setAttribute(WebKeys.CACHE_PORTLET_RESPONSES, responses);
134 }
135
136 return responses;
137 }
138
139 public static Map<String, InvokerPortletResponse> getResponses(
140 PortletSession portletSession) {
141
142 return getResponses(
143 ((PortletSessionImpl)portletSession).getHttpSession());
144 }
145
146 public InvokerPortlet(
147 com.liferay.portal.model.Portlet portletModel, Portlet portlet,
148 PortletContext portletContext)
149 throws PortletException {
150
151 _portletModel = portletModel;
152 _portlet = portlet;
153 _portletContextImpl = (PortletContextImpl)portletContext;
154
155 if (_log.isDebugEnabled()) {
156 _log.debug(
157 "Create root cache wrapper for " +
158 _portletContextImpl.getPortlet().getPortletId());
159 }
160
161 if (ClassUtil.isSubclass(
162 _portlet.getClass(), PortletDeployer.JSF_MYFACES) ||
163 ClassUtil.isSubclass(
164 _portlet.getClass(), PortletDeployer.JSF_SUN)) {
165
166 _facesPortlet = true;
167 }
168
169 _strutsPortlet = ClassUtil.isSubclass(
170 portlet.getClass(), StrutsPortlet.class);
171 _strutsBridgePortlet = ClassUtil.isSubclass(
172 portlet.getClass(),
173 "org.apache.portals.bridges.struts.StrutsPortlet");
174 _expCache = portletModel.getExpCache();
175 setPortletFilters();
176 }
177
178 public InvokerPortlet(
179 com.liferay.portal.model.Portlet portletModel, Portlet portlet,
180 PortletConfig portletConfig, PortletContext portletContext,
181 boolean facesPortlet, boolean strutsPortlet,
182 boolean strutsBridgePortlet)
183 throws PortletException {
184
185
187 _portletModel = portletModel;
188 _portlet = portlet;
189 _portletContextImpl = (PortletContextImpl)portletContext;
190 _facesPortlet = facesPortlet;
191 _strutsPortlet = strutsPortlet;
192 _strutsBridgePortlet = strutsBridgePortlet;
193 _expCache = portletModel.getExpCache();
194 setPortletFilters();
195
196 if (_log.isDebugEnabled()) {
197 _log.debug(
198 "Create instance cache wrapper for " +
199 _portletContextImpl.getPortlet().getPortletId());
200 }
201
202
204 _portletConfigImpl = (PortletConfigImpl)portletConfig;
205
206 _portletId = _portletConfigImpl.getPortletId();
207 }
208
209 public void destroy() {
210 if (_destroyable) {
211 ClassLoader contextClassLoader =
212 Thread.currentThread().getContextClassLoader();
213
214 ClassLoader portletClassLoader = getPortletClassLoader();
215
216 try {
217 if (portletClassLoader != null) {
218 Thread.currentThread().setContextClassLoader(
219 portletClassLoader);
220 }
221
222 _portlet.destroy();
223 }
224 finally {
225 if (portletClassLoader != null) {
226 Thread.currentThread().setContextClassLoader(
227 contextClassLoader);
228 }
229 }
230 }
231
232 _destroyable = false;
233 }
234
235 public ClassLoader getPortletClassLoader() {
236 return (ClassLoader)_portletContextImpl.getAttribute(
237 PortletServlet.PORTLET_CLASS_LOADER);
238 }
239
240 public PortletConfigImpl getPortletConfig() {
241 return _portletConfigImpl;
242 }
243
244 public PortletContextImpl getPortletContext() {
245 return _portletContextImpl;
246 }
247
248 public Portlet getPortletInstance() {
249 return _portlet;
250 }
251
252 public Integer getExpCache() {
253 return _expCache;
254 }
255
256 public void init(PortletConfig portletConfig) throws PortletException {
257 _portletConfigImpl = (PortletConfigImpl)portletConfig;
258
259 _portletId = _portletConfigImpl.getPortletId();
260
261 ClassLoader contextClassLoader =
262 Thread.currentThread().getContextClassLoader();
263
264 ClassLoader portletClassLoader = getPortletClassLoader();
265
266 try {
267 if (portletClassLoader != null) {
268 Thread.currentThread().setContextClassLoader(
269 portletClassLoader);
270 }
271
272 _portlet.init(portletConfig);
273 }
274 finally {
275 if (portletClassLoader != null) {
276 Thread.currentThread().setContextClassLoader(
277 contextClassLoader);
278 }
279 }
280
281 _destroyable = true;
282 }
283
284 public boolean isDestroyable() {
285 return _destroyable;
286 }
287
288 public boolean isFacesPortlet() {
289 return _facesPortlet;
290 }
291
292 public boolean isStrutsBridgePortlet() {
293 return _strutsBridgePortlet;
294 }
295
296 public boolean isStrutsPortlet() {
297 return _strutsPortlet;
298 }
299
300 public void processAction(
301 ActionRequest actionRequest, ActionResponse actionResponse)
302 throws IOException {
303
304 StopWatch stopWatch = null;
305
306 if (_log.isDebugEnabled()) {
307 stopWatch = new StopWatch();
308
309 stopWatch.start();
310 }
311
312 try {
313 invokeAction(actionRequest, actionResponse);
314 }
315 catch (PortletException pe) {
316 actionRequest.setAttribute(
317 _portletId + PortletException.class.getName(), pe);
318 }
319
320 if (_log.isDebugEnabled()) {
321 _log.debug(
322 "processAction for " + _portletId + " takes " +
323 stopWatch.getTime() + " ms");
324 }
325 }
326
327 public void processEvent(
328 EventRequest eventRequest, EventResponse eventResponse)
329 throws IOException, PortletException {
330
331 StopWatch stopWatch = null;
332
333 if (_log.isDebugEnabled()) {
334 stopWatch = new StopWatch();
335
336 stopWatch.start();
337 }
338
339 invokeEvent(eventRequest, eventResponse);
340
341 if (_log.isDebugEnabled()) {
342 _log.debug(
343 "processEvent for " + _portletId + " takes " +
344 stopWatch.getTime() + " ms");
345 }
346 }
347
348 public void render(
349 RenderRequest renderRequest, RenderResponse renderResponse)
350 throws IOException, PortletException {
351
352 PortletException portletException =
353 (PortletException)renderRequest.getAttribute(
354 _portletId + PortletException.class.getName());
355
356 if (portletException != null) {
357 throw portletException;
358 }
359
360 StopWatch stopWatch = null;
361
362 if (_log.isDebugEnabled()) {
363 stopWatch = new StopWatch();
364
365 stopWatch.start();
366 }
367
368 String remoteUser = renderRequest.getRemoteUser();
369
370 if ((remoteUser == null) || (_expCache == null) ||
371 (_expCache.intValue() == 0)) {
372
373 invokeRender(renderRequest, renderResponse);
374 }
375 else {
376 RenderResponseImpl renderResponseImpl =
377 (RenderResponseImpl)renderResponse;
378
379 StringServletResponse stringResponse = (StringServletResponse)
380 renderResponseImpl.getHttpServletResponse();
381
382 PortletSession portletSession = renderRequest.getPortletSession();
383
384 long now = System.currentTimeMillis();
385
386 Layout layout = (Layout)renderRequest.getAttribute(WebKeys.LAYOUT);
387
388 Map<String, InvokerPortletResponse> sessionResponses =
389 getResponses(portletSession);
390
391 String sessionResponseId = encodeResponseKey(
392 layout.getPlid(), _portletId,
393 LanguageUtil.getLanguageId(renderRequest));
394
395 InvokerPortletResponse response = sessionResponses.get(
396 sessionResponseId);
397
398 if (response == null) {
399 String title = invokeRender(renderRequest, renderResponse);
400
401 response = new InvokerPortletResponse(
402 title, stringResponse.getString(),
403 now + Time.SECOND * _expCache.intValue());
404
405 sessionResponses.put(sessionResponseId, response);
406 }
407 else if ((response.getTime() < now) &&
408 (_expCache.intValue() > 0)) {
409
410 String title = invokeRender(renderRequest, renderResponse);
411
412 response.setTitle(title);
413 response.setContent(stringResponse.getString());
414 response.setTime(now + Time.SECOND * _expCache.intValue());
415 }
416 else {
417 renderResponseImpl.setTitle(response.getTitle());
418 stringResponse.getWriter().print(response.getContent());
419 }
420 }
421
422 Map<String, String[]> properties =
423 ((RenderResponseImpl)renderResponse).getProperties();
424
425 if (properties.containsKey("clear-request-parameters")) {
426 Map<String, String[]> renderParameters =
427 ((RenderRequestImpl)renderRequest).getRenderParameters();
428
429 renderParameters.clear();
430 }
431
432 if (_log.isDebugEnabled()) {
433 _log.debug(
434 "render for " + _portletId + " takes " + stopWatch.getTime() +
435 " ms");
436 }
437 }
438
439 public void serveResource(
440 ResourceRequest resourceRequest, ResourceResponse resourceResponse)
441 throws IOException {
442
443 StopWatch stopWatch = null;
444
445 if (_log.isDebugEnabled()) {
446 stopWatch = new StopWatch();
447
448 stopWatch.start();
449 }
450
451 try {
452 invokeResource(resourceRequest, resourceResponse);
453 }
454 catch (PortletException pe) {
455 resourceRequest.setAttribute(
456 _portletId + PortletException.class.getName(), pe);
457 }
458
459 if (_log.isDebugEnabled()) {
460 _log.debug(
461 "serveResource for " + _portletId + " takes " +
462 stopWatch.getTime() + " ms");
463 }
464 }
465
466 public void setPortletFilters() throws PortletException {
467 Map<String, com.liferay.portal.model.PortletFilter> portletFilters =
468 _portletModel.getPortletFilters();
469
470 for (Map.Entry<String, com.liferay.portal.model.PortletFilter> entry :
471 portletFilters.entrySet()) {
472
473 com.liferay.portal.model.PortletFilter portletFilterModel =
474 entry.getValue();
475
476 PortletFilter portletFilter = PortletFilterFactory.create(
477 portletFilterModel, _portletContextImpl);
478
479 Set<String> lifecycles = portletFilterModel.getLifecycles();
480
481 if (lifecycles.contains(PortletRequest.ACTION_PHASE)) {
482 _actionFilters.add((ActionFilter)portletFilter);
483 }
484
485 if (lifecycles.contains(PortletRequest.EVENT_PHASE)) {
486 _eventFilters.add((EventFilter)portletFilter);
487 }
488
489 if (lifecycles.contains(PortletRequest.RENDER_PHASE)) {
490 _renderFilters.add((RenderFilter)portletFilter);
491 }
492
493 if (lifecycles.contains(PortletRequest.RESOURCE_PHASE)) {
494 _resourceFilters.add((ResourceFilter)portletFilter);
495 }
496 }
497 }
498
499 protected void invoke(
500 LiferayPortletRequest portletRequest,
501 LiferayPortletResponse portletResponse, String lifecycle,
502 List<? extends PortletFilter> filters)
503 throws IOException, PortletException {
504
505 FilterChain filterChain = new FilterChainImpl(_portlet, filters);
506
507 if (_portletConfigImpl.isWARFile()) {
508 String path =
509 StringPool.SLASH + _portletConfigImpl.getPortletName() +
510 "/invoke";
511
512 RequestDispatcher requestDispatcher =
513 _portletContextImpl.getServletContext().getRequestDispatcher(
514 path);
515
516 HttpServletRequest request = portletRequest.getHttpServletRequest();
517 HttpServletResponse response =
518 portletResponse.getHttpServletResponse();
519
520 request.setAttribute(JavaConstants.JAVAX_PORTLET_PORTLET, _portlet);
521 request.setAttribute(PortletRequest.LIFECYCLE_PHASE, lifecycle);
522 request.setAttribute(
523 PortletServlet.PORTLET_SERVLET_FILTER_CHAIN, filterChain);
524
525 try {
526
527
530 if (lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
531 requestDispatcher.forward(request, response);
532 }
533 else {
534 requestDispatcher.include(request, response);
535 }
536 }
537 catch (ServletException se) {
538 Throwable cause = se.getRootCause();
539
540 if (cause instanceof PortletException) {
541 throw (PortletException)cause;
542 }
543
544 throw new PortletException(cause);
545 }
546 }
547 else {
548 PortletFilterUtil.doFilter(
549 portletRequest, portletResponse, lifecycle, filterChain);
550 }
551
552 Map<String, String[]> properties = portletResponse.getProperties();
553
554 if ((properties != null) && (properties.size() > 0)) {
555 if (_expCache != null) {
556 String[] expCache = properties.get(
557 RenderResponse.EXPIRATION_CACHE);
558
559 if ((expCache != null) && (expCache.length > 0) &&
560 (expCache[0] != null)) {
561
562 _expCache = new Integer(GetterUtil.getInteger(expCache[0]));
563 }
564 }
565 }
566 }
567
568 protected void invokeAction(
569 ActionRequest actionRequest, ActionResponse actionResponse)
570 throws IOException, PortletException {
571
572 LiferayPortletRequest portletRequest =
573 (LiferayPortletRequest)actionRequest;
574 LiferayPortletResponse portletResponse =
575 (LiferayPortletResponse)actionResponse;
576
577 invoke(
578 portletRequest, portletResponse, PortletRequest.ACTION_PHASE,
579 _actionFilters);
580 }
581
582 protected void invokeEvent(
583 EventRequest eventRequest, EventResponse eventResponse)
584 throws IOException, PortletException {
585
586 LiferayPortletRequest portletRequest =
587 (LiferayPortletRequest)eventRequest;
588 LiferayPortletResponse portletResponse =
589 (LiferayPortletResponse)eventResponse;
590
591 invoke(
592 portletRequest, portletResponse, PortletRequest.EVENT_PHASE,
593 _eventFilters);
594 }
595
596 protected String invokeRender(
597 RenderRequest renderRequest, RenderResponse renderResponse)
598 throws IOException, PortletException {
599
600 LiferayPortletRequest portletRequest =
601 (LiferayPortletRequest)renderRequest;
602 LiferayPortletResponse portletResponse =
603 (LiferayPortletResponse)renderResponse;
604
605 invoke(
606 portletRequest, portletResponse, PortletRequest.RENDER_PHASE,
607 _renderFilters);
608
609 RenderResponseImpl renderResponseImpl =
610 (RenderResponseImpl)renderResponse;
611
612 return renderResponseImpl.getTitle();
613 }
614
615 protected void invokeResource(
616 ResourceRequest resourceRequest, ResourceResponse resourceResponse)
617 throws IOException, PortletException {
618
619 LiferayPortletRequest portletRequest =
620 (LiferayPortletRequest)resourceRequest;
621 LiferayPortletResponse portletResponse =
622 (LiferayPortletResponse)resourceResponse;
623
624 invoke(
625 portletRequest, portletResponse, PortletRequest.RESOURCE_PHASE,
626 _resourceFilters);
627 }
628
629 private static Log _log = LogFactory.getLog(InvokerPortlet.class);
630
631 private com.liferay.portal.model.Portlet _portletModel;
632 private String _portletId;
633 private Portlet _portlet;
634 private PortletConfigImpl _portletConfigImpl;
635 private PortletContextImpl _portletContextImpl;
636 private Integer _expCache;
637 private boolean _destroyable;
638 private boolean _facesPortlet;
639 private boolean _strutsPortlet;
640 private boolean _strutsBridgePortlet;
641 private List<ActionFilter> _actionFilters = new ArrayList<ActionFilter>();
642 private List<EventFilter> _eventFilters = new ArrayList<EventFilter>();
643 private List<RenderFilter> _renderFilters = new ArrayList<RenderFilter>();
644 private List<ResourceFilter> _resourceFilters =
645 new ArrayList<ResourceFilter>();
646
647 }