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