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