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(Portlet portlet, PortletContext portletCtx,
121 Integer expCache) {
122
123 _portlet = portlet;
124 _portletCtx = (PortletContextImpl)portletCtx;
125 _expCache = expCache;
126
127 if (ClassUtil.isSubclass(
128 _portlet.getClass(), PortletDeployer.JSF_MYFACES) ||
129 ClassUtil.isSubclass(
130 _portlet.getClass(), PortletDeployer.JSF_SUN)) {
131
132 _facesPortlet = true;
133 }
134
135 _strutsPortlet = ClassUtil.isSubclass(
136 portlet.getClass(), StrutsPortlet.class);
137 _strutsBridgePortlet = ClassUtil.isSubclass(
138 portlet.getClass(),
139 "org.apache.portals.bridges.struts.StrutsPortlet");
140 }
141
142 public void init(PortletConfig config) throws PortletException {
143 _portletConfig = (PortletConfigImpl)config;
144
145 _portletId = _portletConfig.getPortletId();
146
147 ClassLoader contextClassLoader =
148 Thread.currentThread().getContextClassLoader();
149
150 ClassLoader portletClassLoader = _getPortletClassLoader();
151
152 try {
153 if (portletClassLoader != null) {
154 Thread.currentThread().setContextClassLoader(
155 portletClassLoader);
156 }
157
158 _portlet.init(config);
159 }
160 finally {
161 if (portletClassLoader != null) {
162 Thread.currentThread().setContextClassLoader(
163 contextClassLoader);
164 }
165 }
166
167 _destroyable = true;
168 }
169
170 public void processAction(ActionRequest req, ActionResponse res)
171 throws IOException, PortletException {
172
173 StopWatch stopWatch = null;
174
175 if (_log.isDebugEnabled()) {
176 stopWatch = new StopWatch();
177
178 stopWatch.start();
179 }
180
181 try {
182 _invoke(req, res, true);
183 }
184 catch (PortletException pe) {
185 req.setAttribute(_portletId + PortletException.class.getName(), pe);
186 }
187
188 if (_log.isDebugEnabled()) {
189 _log.debug(
190 "processAction for " + _portletId + " takes " +
191 stopWatch.getTime() + " ms");
192 }
193 }
194
195 public void render(RenderRequest req, RenderResponse res)
196 throws IOException, PortletException {
197
198 PortletException portletException = (PortletException)req.getAttribute(
199 _portletId + PortletException.class.getName());
200
201 if (portletException != null) {
202 throw portletException;
203 }
204
205 StopWatch stopWatch = null;
206
207 if (_log.isDebugEnabled()) {
208 stopWatch = new StopWatch();
209
210 stopWatch.start();
211 }
212
213 String remoteUser = req.getRemoteUser();
214
215 if ((remoteUser == null) || (_expCache == null) ||
216 (_expCache.intValue() == 0)) {
217
218 _invoke(req, res, false);
219 }
220 else {
221 RenderResponseImpl resImpl = (RenderResponseImpl)res;
222
223 StringServletResponse stringServletRes =
224 (StringServletResponse)resImpl.getHttpServletResponse();
225
226 PortletSession ses = req.getPortletSession();
227
228 long now = System.currentTimeMillis();
229
230 Layout layout = (Layout)req.getAttribute(WebKeys.LAYOUT);
231
232 Map sesResponses = getResponses(ses);
233
234 String sesResponseId = encodeResponseKey(
235 layout.getPlid(), _portletId, LanguageUtil.getLanguageId(req));
236
237 CachePortletResponse response =
238 (CachePortletResponse)sesResponses.get(sesResponseId);
239
240 if (response == null) {
241 _invoke(req, res, false);
242
243 response = new CachePortletResponse(
244 resImpl.getTitle(),
245 stringServletRes.getString(),
246 now + Time.SECOND * _expCache.intValue());
247
248 sesResponses.put(sesResponseId, response);
249 }
250 else if ((response.getTime() < now) &&
251 (_expCache.intValue() > 0)) {
252
253 _invoke(req, res, false);
254
255 response.setTitle(resImpl.getTitle());
256 response.setContent(stringServletRes.getString());
257 response.setTime(now + Time.SECOND * _expCache.intValue());
258 }
259 else {
260 resImpl.setTitle(response.getTitle());
261 stringServletRes.getWriter().print(response.getContent());
262 }
263 }
264
265 if (_log.isDebugEnabled()) {
266 _log.debug(
267 "render for " + _portletId + " takes " + stopWatch.getTime() +
268 " ms");
269 }
270 }
271
272 public void destroy() {
273 if (_destroyable) {
274 ClassLoader contextClassLoader =
275 Thread.currentThread().getContextClassLoader();
276
277 ClassLoader portletClassLoader = _getPortletClassLoader();
278
279 try {
280 if (portletClassLoader != null) {
281 Thread.currentThread().setContextClassLoader(
282 portletClassLoader);
283 }
284
285 _portlet.destroy();
286 }
287 finally {
288 if (portletClassLoader != null) {
289 Thread.currentThread().setContextClassLoader(
290 contextClassLoader);
291 }
292 }
293 }
294
295 _destroyable = false;
296 }
297
298 public Portlet getPortletInstance() {
299 return _portlet;
300 }
301
302 public PortletConfigImpl getPortletConfig() {
303 return _portletConfig;
304 }
305
306 public PortletContextImpl getPortletContext() {
307 return _portletCtx;
308 }
309
310 public boolean isDestroyable() {
311 return _destroyable;
312 }
313
314 public boolean isFacesPortlet() {
315 return _facesPortlet;
316 }
317
318 public boolean isStrutsPortlet() {
319 return _strutsPortlet;
320 }
321
322 public boolean isStrutsBridgePortlet() {
323 return _strutsBridgePortlet;
324 }
325
326 private ClassLoader _getPortletClassLoader() {
327 return (ClassLoader)_portletCtx.getAttribute(
328 PortletServlet.PORTLET_CLASS_LOADER);
329 }
330
331 private void _invoke(
332 PortletRequest req, PortletResponse res, boolean action)
333 throws IOException, PortletException {
334
335 Map properties = null;
336
337 if (_portletConfig.isWARFile()) {
338 String path =
339 StringPool.SLASH + _portletConfig.getPortletName() + "/invoke";
340
341 RequestDispatcher rd =
342 _portletCtx.getServletContext().getRequestDispatcher(path);
343
344 HttpServletRequest httpReq = null;
345 HttpServletResponse httpRes = null;
346
347 ActionRequestImpl actionReqImpl = null;
348 ActionResponseImpl actionResImpl = null;
349
350 RenderRequestImpl renderReqImpl = null;
351 RenderResponseImpl renderResImpl = null;
352
353 if (action) {
354 actionReqImpl = (ActionRequestImpl)req;
355 actionResImpl = (ActionResponseImpl)res;
356
357 httpReq = actionReqImpl.getHttpServletRequest();
358 httpRes = actionResImpl.getHttpServletResponse();
359 }
360 else {
361 renderReqImpl = (RenderRequestImpl)req;
362 renderResImpl = (RenderResponseImpl)res;
363
364 httpReq = renderReqImpl.getHttpServletRequest();
365 httpRes = renderResImpl.getHttpServletResponse();
366 }
367
368 httpReq.setAttribute(JavaConstants.JAVAX_PORTLET_PORTLET, _portlet);
369
370 try {
371 rd.include(httpReq, httpRes);
372 }
373 catch (ServletException se) {
374 Throwable cause = se.getRootCause();
375
376 if (cause instanceof PortletException) {
377 throw (PortletException)cause;
378 }
379
380 throw new PortletException(cause);
381 }
382
383 if (action) {
384 properties = actionResImpl.getProperties();
385 }
386 else {
387 properties = renderResImpl.getProperties();
388 }
389 }
390 else {
391 if (action) {
392 ActionRequestImpl actionReqImpl = (ActionRequestImpl)req;
393 ActionResponseImpl actionResImpl = (ActionResponseImpl)res;
394
395 _portlet.processAction(actionReqImpl, actionResImpl);
396
397 properties = actionResImpl.getProperties();
398 }
399 else {
400 RenderRequestImpl renderReqImpl = (RenderRequestImpl)req;
401 RenderResponseImpl renderResImpl = (RenderResponseImpl)res;
402
403 _portlet.render(renderReqImpl, renderResImpl);
404
405 properties = renderResImpl.getProperties();
406 }
407 }
408
409 if ((properties != null) && (properties.size() > 0)) {
410 if (_expCache != null) {
411 String[] expCache = (String[])properties.get(
412 RenderResponse.EXPIRATION_CACHE);
413
414 if ((expCache != null) && (expCache.length > 0) &&
415 (expCache[0] != null)) {
416
417 _expCache = new Integer(GetterUtil.getInteger(expCache[0]));
418 }
419 }
420 }
421 }
422
423 private static Log _log = LogFactory.getLog(CachePortlet.class);
424
425 private String _portletId;
426 private Portlet _portlet;
427 private PortletConfigImpl _portletConfig;
428 private PortletContextImpl _portletCtx;
429 private Integer _expCache;
430 private boolean _destroyable;
431 private boolean _facesPortlet;
432 private boolean _strutsPortlet;
433 private boolean _strutsBridgePortlet;
434
435 }