1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.jetspeed.aggregator.impl;
19
20 import java.util.Iterator;
21 import java.util.Map;
22 import java.util.HashMap;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.Arrays;
26
27 import javax.portlet.UnavailableException;
28 import javax.servlet.ServletRequest;
29 import javax.servlet.http.HttpServletRequest;
30 import javax.servlet.http.HttpServletResponse;
31 import javax.servlet.http.HttpServletRequestWrapper;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.jetspeed.PortalReservedParameters;
36 import org.apache.jetspeed.aggregator.ContentDispatcherCtrl;
37 import org.apache.jetspeed.aggregator.CurrentWorkerContext;
38 import org.apache.jetspeed.aggregator.PortletContent;
39 import org.apache.jetspeed.aggregator.PortletRenderer;
40 import org.apache.jetspeed.aggregator.PortletTrackingManager;
41 import org.apache.jetspeed.aggregator.RenderingJob;
42 import org.apache.jetspeed.components.portletentity.PortletEntityImpl;
43 import org.apache.jetspeed.om.common.portlet.MutablePortletEntity;
44 import org.apache.jetspeed.om.page.ContentFragment;
45 import org.apache.jetspeed.request.RequestContext;
46 import org.apache.jetspeed.statistics.PortalStatistics;
47 import org.apache.pluto.PortletContainer;
48 import org.apache.pluto.om.portlet.PortletDefinition;
49 import org.apache.pluto.om.window.PortletWindow;
50
51 /***
52 * The RenderingJob is responsible for storing all necessary objets for
53 * asynchronous portlet rendering as well as implementing the rendering logic
54 * in its Runnable method.
55 *
56 * @author <a href="mailto:raphael@apache.org">Rapha?l Luta</a>
57 * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
58 * @author <a>Woonsan Ko</a>
59 * @version $Id: RenderingJobImpl.java 592263 2007-11-06 04:19:20Z woonsan $
60 */
61 public class RenderingJobImpl implements RenderingJob
62 {
63 /*** Commons logging */
64 protected final static Log log = LogFactory.getLog(RenderingJobImpl.class);
65
66 /*** WorkerMonitor used to flush the queue */
67 protected PortletWindow window = null;
68 protected HttpServletRequest request = null;
69 protected HttpServletResponse response = null;
70
71 protected PortletContainer container = null;
72 protected PortletRenderer renderer = null;
73 protected ContentFragment fragment = null;
74 protected RequestContext requestContext = null;
75 protected PortletTrackingManager portletTracking = null;
76
77 protected PortletDefinition portletDefinition;
78 protected PortletContent portletContent;
79 protected PortalStatistics statistics;
80 protected ContentDispatcherCtrl dispatcher;
81 protected boolean contentIsCached;
82
83 protected int expirationCache = 0;
84
85 protected Map workerAttributes;
86
87 protected long startTimeMillis = 0;
88 protected long timeout;
89
90 public RenderingJobImpl(PortletContainer container,
91 PortletRenderer renderer,
92 PortletDefinition portletDefinition,
93 PortletContent portletContent,
94 ContentFragment fragment,
95 ContentDispatcherCtrl dispatcher,
96 HttpServletRequest request,
97 HttpServletResponse response,
98 RequestContext requestContext,
99 PortletWindow window,
100 PortalStatistics statistics,
101 int expirationCache,
102 boolean contentIsCached)
103 {
104 this.container = container;
105 this.renderer = renderer;
106 this.portletTracking = renderer.getPortletTrackingManager();
107 this.statistics = statistics;
108 this.portletDefinition = portletDefinition;
109 this.fragment = fragment;
110 this.dispatcher = dispatcher;
111 this.request = request;
112 this.response = response;
113 this.requestContext = requestContext;
114 this.window = window;
115 this.portletContent = portletContent;
116 ((MutablePortletEntity)window.getPortletEntity()).setFragment(fragment);
117 this.expirationCache = expirationCache;
118 this.contentIsCached = contentIsCached;
119 }
120
121 public RenderingJobImpl(PortletContainer container,
122 PortletRenderer renderer,
123 PortletDefinition portletDefinition,
124 PortletContent portletContent,
125 ContentFragment fragment,
126 ContentDispatcherCtrl dispatcher,
127 HttpServletRequest request,
128 HttpServletResponse response,
129 RequestContext requestContext,
130 PortletWindow window,
131 PortalStatistics statistics,
132 int expirationCache,
133 boolean contentIsCached,
134 Map workerAttrs)
135 {
136 this(container, renderer, portletDefinition, portletContent, fragment, dispatcher,
137 request, response, requestContext, window, statistics, expirationCache, contentIsCached);
138
139 if (workerAttrs != null)
140 {
141 this.workerAttributes = Collections.synchronizedMap(workerAttrs);
142 }
143 }
144
145 /***
146 * Sets portlet timout in milliseconds.
147 */
148 public void setTimeout(long timeout) {
149 this.timeout = timeout;
150 }
151
152 /***
153 * Gets portlet timout in milliseconds.
154 */
155 public long getTimeout() {
156 return this.timeout;
157 }
158
159 /***
160 * Checks if the portlet rendering is timeout
161 */
162 public boolean isTimeout() {
163 if ((this.timeout > 0) && (this.startTimeMillis > 0)) {
164 return (System.currentTimeMillis() - this.startTimeMillis > this.timeout);
165 }
166
167 return false;
168 }
169
170 /***
171 * Checks if queue is empty, if not try to empty it by calling
172 * the WorkerMonitor. When done, pause until next scheduled scan.
173 */
174 public void run()
175 {
176 try
177 {
178 if (this.timeout > 0)
179 {
180 CurrentWorkerContext.setParallelRenderingMode(true);
181 this.startTimeMillis = System.currentTimeMillis();
182 }
183
184
185 fragment.setPortletContent(portletContent);
186 execute();
187 }
188 finally
189 {
190 synchronized (portletContent)
191 {
192 if (log.isDebugEnabled()) log.debug("Notifying completion of rendering job for fragment " + fragment.getId());
193 portletContent.notifyAll();
194 }
195 }
196 }
197
198 /***
199 * <p>
200 * execute
201 * </p>
202 *
203 *
204 */
205 public void execute()
206 {
207 long start = System.currentTimeMillis();
208 boolean isParallelMode = false;
209 PortletWindow curWindow = this.window;
210 try
211 {
212 if (log.isDebugEnabled()) log.debug("Rendering OID "+this.window.getId()+" "+ this.request +" "+this.response);
213
214
215 if (this.workerAttributes != null)
216 {
217 isParallelMode = CurrentWorkerContext.getParallelRenderingMode();
218 if (isParallelMode)
219 {
220 Collection attrNames = Arrays.asList(this.workerAttributes.keySet().toArray());
221
222 Iterator itAttrNames = attrNames.iterator();
223 while (itAttrNames.hasNext())
224 {
225 String name = (String) itAttrNames.next();
226 CurrentWorkerContext.setAttribute(name, this.workerAttributes.get(name));
227 }
228
229
230
231
232
233
234
235
236 curWindow = (PortletWindow)
237 CurrentWorkerContext.getAttribute(PortalReservedParameters.PORTLET_WINDOW_ATTRIBUTE);
238 PortletEntityImpl curEntity = (PortletEntityImpl) curWindow.getPortletEntity();
239 PortletDefinition oldPortletDefinition = curEntity.getPortletDefinition();
240 PortletDefinition curPortletDefinition = (PortletDefinition)
241 CurrentWorkerContext.getAttribute(PortalReservedParameters.PORTLET_DEFINITION_ATTRIBUTE);
242
243 if (!oldPortletDefinition.getId().equals(curPortletDefinition.getId())) {
244 curEntity.setPortletDefinition(curPortletDefinition);
245 }
246 }
247 }
248
249 if (isParallelMode)
250 {
251 ServletRequest servletRequest = ((HttpServletRequestWrapper)((HttpServletRequestWrapper) this.request).getRequest()).getRequest();
252
253 synchronized (servletRequest)
254 {
255 this.request.setAttribute(PortalReservedParameters.FRAGMENT_ATTRIBUTE, fragment);
256 this.request.setAttribute(PortalReservedParameters.PAGE_ATTRIBUTE, requestContext.getPage());
257 this.request.setAttribute(PortalReservedParameters.REQUEST_CONTEXT_ATTRIBUTE, requestContext);
258 this.request.setAttribute(PortalReservedParameters.REQUEST_CONTEXT_OBJECTS, requestContext.getObjects());
259
260 }
261 }
262 else
263 {
264 this.request.setAttribute(PortalReservedParameters.FRAGMENT_ATTRIBUTE, fragment);
265 this.request.setAttribute(PortalReservedParameters.PAGE_ATTRIBUTE, requestContext.getPage());
266 this.request.setAttribute(PortalReservedParameters.REQUEST_CONTEXT_ATTRIBUTE, requestContext);
267 this.request.setAttribute(PortalReservedParameters.REQUEST_CONTEXT_OBJECTS, requestContext.getObjects());
268
269 }
270
271 container.renderPortlet(this.window, this.request, this.response);
272 this.response.flushBuffer();
273 }
274 catch (Throwable t)
275 {
276 if (t instanceof UnavailableException)
277 {
278
279 log.error("Error rendering portlet OID " + curWindow.getId() + ": " + t.toString());
280 }
281 else
282 {
283 log.error("Error rendering portlet OID " + curWindow.getId(), t);
284 }
285 fragment.overrideRenderedContent(t.getMessage());
286 }
287 finally
288 {
289 try
290 {
291 if (isParallelMode)
292 {
293 this.renderer.addTitleToHeader(curWindow, fragment,
294 this.request, this.response,
295 this.dispatcher, this.contentIsCached);
296
297 CurrentWorkerContext.removeAllAttributes();
298 }
299
300 if (fragment.getType().equals(ContentFragment.PORTLET))
301 {
302 long end = System.currentTimeMillis();
303 boolean exceededTimeout = portletTracking.exceededTimeout(end - start, window);
304
305 if (statistics != null)
306 {
307 statistics.logPortletAccess(requestContext, fragment.getName(), PortalStatistics.HTTP_OK, end - start);
308 }
309 if (exceededTimeout)
310 {
311
312 log.info("Portlet Exceeded timeout: " + curWindow.getPortletEntity().getPortletDefinition().getName() + " for window " + curWindow.getId());
313 portletTracking.incrementRenderTimeoutCount(curWindow);
314 }
315 else
316 {
317 portletTracking.success(curWindow);
318 }
319 }
320 }
321 finally
322 {
323 synchronized (portletContent)
324 {
325 if (fragment.getOverriddenContent() != null)
326 {
327 portletContent.completeWithError();
328 }
329 else
330 {
331 portletContent.complete();
332 }
333 }
334 }
335 }
336 }
337
338 /***
339 *
340 * <p>
341 * getWindow
342 * </p>
343 *
344 * @return The window this job is in charge of rendering
345 */
346 public PortletWindow getWindow()
347 {
348 return window;
349 }
350
351 /***
352 *
353 * <p>
354 * getPortletContent
355 * </p>
356 *
357 * @return The portlet content this job is in charge of rendering
358 */
359 public PortletContent getPortletContent()
360 {
361 return portletContent;
362 }
363
364 public PortletDefinition getPortletDefinition()
365 {
366 return this.portletDefinition;
367 }
368
369 public HttpServletRequest getRequest()
370 {
371 return this.request;
372 }
373
374 public HttpServletResponse getResponse()
375 {
376 return this.response;
377 }
378
379 public ContentFragment getFragment()
380 {
381 return this.fragment;
382 }
383
384 public RequestContext getRequestContext()
385 {
386 return this.requestContext;
387 }
388
389 public int getExpirationCache()
390 {
391 return this.expirationCache;
392 }
393
394 public ContentDispatcherCtrl getDispatcher()
395 {
396 return this.dispatcher;
397 }
398
399 public boolean isContentCached()
400 {
401 return this.contentIsCached;
402 }
403
404 public void setWorkerAttribute(String name, Object value)
405 {
406 if (this.workerAttributes == null)
407 {
408 this.workerAttributes = Collections.synchronizedMap(new HashMap());
409 }
410
411 if (value != null)
412 {
413 this.workerAttributes.put(name, value);
414 }
415 else
416 {
417 this.workerAttributes.remove(name);
418 }
419 }
420
421 public Object getWorkerAttribute(String name)
422 {
423 Object value = null;
424
425 if (this.workerAttributes != null)
426 {
427 value = this.workerAttributes.get(name);
428 }
429
430 return value;
431 }
432
433 public void removeWorkerAttribute(String name)
434 {
435 if (this.workerAttributes != null)
436 {
437 this.workerAttributes.remove(name);
438 }
439 }
440 }