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.CollectionFactory;
37 import com.liferay.util.Time;
38
39 import java.io.IOException;
40
41 import java.util.Map;
42
43 import javax.portlet.ActionRequest;
44 import javax.portlet.ActionResponse;
45 import javax.portlet.Portlet;
46 import javax.portlet.PortletConfig;
47 import javax.portlet.PortletContext;
48 import javax.portlet.PortletException;
49 import javax.portlet.PortletRequest;
50 import javax.portlet.PortletResponse;
51 import javax.portlet.PortletSession;
52 import javax.portlet.RenderRequest;
53 import javax.portlet.RenderResponse;
54
55 import javax.servlet.RequestDispatcher;
56 import javax.servlet.ServletException;
57 import javax.servlet.http.HttpServletRequest;
58 import javax.servlet.http.HttpServletResponse;
59 import javax.servlet.http.HttpSession;
60
61 import org.apache.commons.lang.time.StopWatch;
62 import org.apache.commons.logging.Log;
63 import org.apache.commons.logging.LogFactory;
64
65
72 public class CachePortlet implements Portlet {
73
74 public static void clearResponse(
75 HttpSession ses, long plid, String portletId, String languageId) {
76
77 String sesResponseId = encodeResponseKey(plid, portletId, languageId);
78
79 getResponses(ses).remove(sesResponseId);
80 }
81
82 public static void clearResponses(HttpSession ses) {
83 getResponses(ses).clear();
84 }
85
86 public static void clearResponses(PortletSession ses) {
87 getResponses(ses).clear();
88 }
89
90 public static String encodeResponseKey(
91 long plid, String portletId, String languageId) {
92
93 StringMaker sm = new StringMaker();
94
95 sm.append(plid);
96 sm.append(StringPool.UNDERLINE);
97 sm.append(portletId);
98 sm.append(StringPool.UNDERLINE);
99 sm.append(languageId);
100
101 return sm.toString();
102 }
103
104 public static Map getResponses(HttpSession ses) {
105 Map responses = (Map)ses.getAttribute(WebKeys.CACHE_PORTLET_RESPONSES);
106
107 if (responses == null) {
108 responses = CollectionFactory.getHashMap();
109
110 ses.setAttribute(WebKeys.CACHE_PORTLET_RESPONSES, responses);
111 }
112
113 return responses;
114 }
115
116 public static Map getResponses(PortletSession ses) {
117 return getResponses(((PortletSessionImpl)ses).getHttpSession());
118 }
119
120 public CachePortlet(
121 Portlet portlet, PortletContext portletCtx, Integer expCache) {
122
123 _portlet = portlet;
124 _portletCtx = (PortletContextImpl)portletCtx;
125 _expCache = expCache;
126
127 if (_log.isDebugEnabled()) {
128 _log.debug(
129 "Create root cache wrapper for " +
130 _portletCtx.getPortlet().getPortletId());
131 }
132
133 if (ClassUtil.isSubclass(
134 _portlet.getClass(), PortletDeployer.JSF_MYFACES) ||
135 ClassUtil.isSubclass(
136 _portlet.getClass(), PortletDeployer.JSF_SUN)) {
137
138 _facesPortlet = true;
139 }
140
141 _strutsPortlet = ClassUtil.isSubclass(
142 portlet.getClass(), StrutsPortlet.class);
143 _strutsBridgePortlet = ClassUtil.isSubclass(
144 portlet.getClass(),
145 "org.apache.portals.bridges.struts.StrutsPortlet");
146 }
147
148 public CachePortlet(
149 Portlet portlet, PortletConfig portletConfig, PortletContext portletCtx,
150 Integer expCache, boolean facesPortlet, boolean strutsPortlet,
151 boolean strutsBridgePortlet) {
152
153
155 _portlet = portlet;
156 _portletCtx = (PortletContextImpl)portletCtx;
157 _expCache = expCache;
158 _facesPortlet = facesPortlet;
159 _strutsPortlet = strutsPortlet;
160 _strutsBridgePortlet = strutsBridgePortlet;
161
162 if (_log.isDebugEnabled()) {
163 _log.debug(
164 "Create instance cache wrapper for " +
165 _portletCtx.getPortlet().getPortletId());
166 }
167
168
170 _portletConfig = (PortletConfigImpl)portletConfig;
171
172 _portletId = _portletConfig.getPortletId();
173 }
174
175 public void init(PortletConfig portletConfig) throws PortletException {
176 _portletConfig = (PortletConfigImpl)portletConfig;
177
178 _portletId = _portletConfig.getPortletId();
179
180 ClassLoader contextClassLoader =
181 Thread.currentThread().getContextClassLoader();
182
183 ClassLoader portletClassLoader = _getPortletClassLoader();
184
185 try {
186 if (portletClassLoader != null) {
187 Thread.currentThread().setContextClassLoader(
188 portletClassLoader);
189 }
190
191 _portlet.init(portletConfig);
192 }
193 finally {
194 if (portletClassLoader != null) {
195 Thread.currentThread().setContextClassLoader(
196 contextClassLoader);
197 }
198 }
199
200 _destroyable = true;
201 }
202
203 public void processAction(ActionRequest req, ActionResponse res)
204 throws IOException, PortletException {
205
206 StopWatch stopWatch = null;
207
208 if (_log.isDebugEnabled()) {
209 stopWatch = new StopWatch();
210
211 stopWatch.start();
212 }
213
214 try {
215 _invoke(req, res, true);
216 }
217 catch (PortletException pe) {
218 req.setAttribute(_portletId + PortletException.class.getName(), pe);
219 }
220
221 if (_log.isDebugEnabled()) {
222 _log.debug(
223 "processAction for " + _portletId + " takes " +
224 stopWatch.getTime() + " ms");
225 }
226 }
227
228 public void render(RenderRequest req, RenderResponse res)
229 throws IOException, PortletException {
230
231 PortletException portletException = (PortletException)req.getAttribute(
232 _portletId + PortletException.class.getName());
233
234 if (portletException != null) {
235 throw portletException;
236 }
237
238 StopWatch stopWatch = null;
239
240 if (_log.isDebugEnabled()) {
241 stopWatch = new StopWatch();
242
243 stopWatch.start();
244 }
245
246 String remoteUser = req.getRemoteUser();
247
248 if ((remoteUser == null) || (_expCache == null) ||
249 (_expCache.intValue() == 0)) {
250
251 _invoke(req, res, false);
252 }
253 else {
254 RenderResponseImpl resImpl = (RenderResponseImpl)res;
255
256 StringServletResponse stringServletRes =
257 (StringServletResponse)resImpl.getHttpServletResponse();
258
259 PortletSession ses = req.getPortletSession();
260
261 long now = System.currentTimeMillis();
262
263 Layout layout = (Layout)req.getAttribute(WebKeys.LAYOUT);
264
265 Map sesResponses = getResponses(ses);
266
267 String sesResponseId = encodeResponseKey(
268 layout.getPlid(), _portletId, LanguageUtil.getLanguageId(req));
269
270 CachePortletResponse response =
271 (CachePortletResponse)sesResponses.get(sesResponseId);
272
273 if (response == null) {
274 _invoke(req, res, false);
275
276 response = new CachePortletResponse(
277 resImpl.getTitle(),
278 stringServletRes.getString(),
279 now + Time.SECOND * _expCache.intValue());
280
281 sesResponses.put(sesResponseId, response);
282 }
283 else if ((response.getTime() < now) &&
284 (_expCache.intValue() > 0)) {
285
286 _invoke(req, res, false);
287
288 response.setTitle(resImpl.getTitle());
289 response.setContent(stringServletRes.getString());
290 response.setTime(now + Time.SECOND * _expCache.intValue());
291 }
292 else {
293 resImpl.setTitle(response.getTitle());
294 stringServletRes.getWriter().print(response.getContent());
295 }
296 }
297
298 if (_log.isDebugEnabled()) {
299 _log.debug(
300 "render for " + _portletId + " takes " + stopWatch.getTime() +
301 " ms");
302 }
303 }
304
305 public void destroy() {
306 if (_destroyable) {
307 ClassLoader contextClassLoader =
308 Thread.currentThread().getContextClassLoader();
309
310 ClassLoader portletClassLoader = _getPortletClassLoader();
311
312 try {
313 if (portletClassLoader != null) {
314 Thread.currentThread().setContextClassLoader(
315 portletClassLoader);
316 }
317
318 _portlet.destroy();
319 }
320 finally {
321 if (portletClassLoader != null) {
322 Thread.currentThread().setContextClassLoader(
323 contextClassLoader);
324 }
325 }
326 }
327
328 _destroyable = false;
329 }
330
331 public Portlet getPortletInstance() {
332 return _portlet;
333 }
334
335 public PortletConfigImpl getPortletConfig() {
336 return _portletConfig;
337 }
338
339 public PortletContextImpl getPortletContext() {
340 return _portletCtx;
341 }
342
343 public Integer getExpCache() {
344 return _expCache;
345 }
346
347 public boolean isDestroyable() {
348 return _destroyable;
349 }
350
351 public boolean isFacesPortlet() {
352 return _facesPortlet;
353 }
354
355 public boolean isStrutsPortlet() {
356 return _strutsPortlet;
357 }
358
359 public boolean isStrutsBridgePortlet() {
360 return _strutsBridgePortlet;
361 }
362
363 private ClassLoader _getPortletClassLoader() {
364 return (ClassLoader)_portletCtx.getAttribute(
365 PortletServlet.PORTLET_CLASS_LOADER);
366 }
367
368 private void _invoke(
369 PortletRequest req, PortletResponse res, boolean action)
370 throws IOException, PortletException {
371
372 Map properties = null;
373
374 if (_portletConfig.isWARFile()) {
375 String path =
376 StringPool.SLASH + _portletConfig.getPortletName() + "/invoke";
377
378 RequestDispatcher rd =
379 _portletCtx.getServletContext().getRequestDispatcher(path);
380
381 HttpServletRequest httpReq = null;
382 HttpServletResponse httpRes = null;
383
384 ActionRequestImpl actionReqImpl = null;
385 ActionResponseImpl actionResImpl = null;
386
387 RenderRequestImpl renderReqImpl = null;
388 RenderResponseImpl renderResImpl = null;
389
390 if (action) {
391 actionReqImpl = (ActionRequestImpl)req;
392 actionResImpl = (ActionResponseImpl)res;
393
394 httpReq = actionReqImpl.getHttpServletRequest();
395 httpRes = actionResImpl.getHttpServletResponse();
396 }
397 else {
398 renderReqImpl = (RenderRequestImpl)req;
399 renderResImpl = (RenderResponseImpl)res;
400
401 httpReq = renderReqImpl.getHttpServletRequest();
402 httpRes = renderResImpl.getHttpServletResponse();
403 }
404
405 httpReq.setAttribute(JavaConstants.JAVAX_PORTLET_PORTLET, _portlet);
406
407 try {
408 rd.include(httpReq, httpRes);
409 }
410 catch (ServletException se) {
411 Throwable cause = se.getRootCause();
412
413 if (cause instanceof PortletException) {
414 throw (PortletException)cause;
415 }
416
417 throw new PortletException(cause);
418 }
419
420 if (action) {
421 properties = actionResImpl.getProperties();
422 }
423 else {
424 properties = renderResImpl.getProperties();
425 }
426 }
427 else {
428 if (action) {
429 ActionRequestImpl actionReqImpl = (ActionRequestImpl)req;
430 ActionResponseImpl actionResImpl = (ActionResponseImpl)res;
431
432 _portlet.processAction(actionReqImpl, actionResImpl);
433
434 properties = actionResImpl.getProperties();
435 }
436 else {
437 RenderRequestImpl renderReqImpl = (RenderRequestImpl)req;
438 RenderResponseImpl renderResImpl = (RenderResponseImpl)res;
439
440 _portlet.render(renderReqImpl, renderResImpl);
441
442 properties = renderResImpl.getProperties();
443 }
444 }
445
446 if ((properties != null) && (properties.size() > 0)) {
447 if (_expCache != null) {
448 String[] expCache = (String[])properties.get(
449 RenderResponse.EXPIRATION_CACHE);
450
451 if ((expCache != null) && (expCache.length > 0) &&
452 (expCache[0] != null)) {
453
454 _expCache = new Integer(GetterUtil.getInteger(expCache[0]));
455 }
456 }
457 }
458 }
459
460 private static Log _log = LogFactory.getLog(CachePortlet.class);
461
462 private String _portletId;
463 private Portlet _portlet;
464 private PortletConfigImpl _portletConfig;
465 private PortletContextImpl _portletCtx;
466 private Integer _expCache;
467 private boolean _destroyable;
468 private boolean _facesPortlet;
469 private boolean _strutsPortlet;
470 private boolean _strutsBridgePortlet;
471
472 }