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