View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.jetspeed.aggregator.impl;
19  
20  import java.util.Iterator;
21  import java.util.Map;
22  
23  import javax.portlet.UnavailableException;
24  import javax.servlet.http.HttpServletRequest;
25  import javax.servlet.http.HttpServletResponse;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.jetspeed.PortalReservedParameters;
30  import org.apache.jetspeed.aggregator.ContentDispatcherCtrl;
31  import org.apache.jetspeed.aggregator.CurrentWorkerContext;
32  import org.apache.jetspeed.aggregator.PortletContent;
33  import org.apache.jetspeed.aggregator.PortletRenderer;
34  import org.apache.jetspeed.aggregator.PortletTrackingManager;
35  import org.apache.jetspeed.aggregator.RenderingJob;
36  import org.apache.jetspeed.aggregator.Worker;
37  import org.apache.jetspeed.components.portletentity.PortletEntityImpl;
38  import org.apache.jetspeed.om.common.portlet.MutablePortletEntity;
39  import org.apache.jetspeed.om.page.ContentFragment;
40  import org.apache.jetspeed.request.RequestContext;
41  import org.apache.jetspeed.statistics.PortalStatistics;
42  import org.apache.pluto.PortletContainer;
43  import org.apache.pluto.om.portlet.PortletDefinition;
44  import org.apache.pluto.om.window.PortletWindow;
45  
46  /***
47   * The RenderingJob is responsible for storing all necessary objets for
48   * asynchronous portlet rendering as well as implementing the rendering logic
49   * in its Runnable method.
50   *
51   * @author <a href="mailto:raphael@apache.org">Rapha?l Luta</a>
52   * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
53   * @author <a>Woonsan Ko</a>
54   * @version $Id: RenderingJobImpl.java 554827 2007-07-10 05:12:23Z taylor $
55   */
56  public class RenderingJobImpl implements RenderingJob
57  {
58      /*** Commons logging */
59      protected final static Log log = LogFactory.getLog(RenderingJobImpl.class);
60  
61      /*** WorkerMonitor used to flush the queue */
62      protected PortletWindow window = null;
63      protected HttpServletRequest request = null;
64      protected HttpServletResponse response = null;
65      
66      protected PortletContainer container = null;
67      protected PortletRenderer renderer = null;
68      protected ContentFragment fragment = null;
69      protected RequestContext requestContext = null;
70      protected PortletTrackingManager portletTracking = null;
71  
72      protected PortletDefinition portletDefinition;
73      protected PortletContent portletContent;
74      protected PortalStatistics statistics;
75      protected ContentDispatcherCtrl dispatcher;
76      protected boolean contentIsCached;
77      
78      protected int expirationCache = 0;
79  
80      protected Map workerAttributes;
81  
82      protected long startTimeMillis = 0;
83      protected long timeout;
84      
85      public RenderingJobImpl(PortletContainer container,
86                              PortletRenderer renderer,
87                              PortletDefinition portletDefinition,
88                              PortletContent portletContent, 
89                              ContentFragment fragment, 
90                              ContentDispatcherCtrl dispatcher,
91                              HttpServletRequest request, 
92                              HttpServletResponse response, 
93                              RequestContext requestContext, 
94                              PortletWindow window,
95                              PortalStatistics statistics,
96                              int expirationCache,
97                              boolean contentIsCached)
98      {
99          this.container = container;
100         this.renderer = renderer;
101         this.portletTracking = renderer.getPortletTrackingManager();        
102         this.statistics = statistics;
103         this.portletDefinition = portletDefinition;
104         this.fragment = fragment;
105         this.dispatcher = dispatcher;
106         this.request = request;
107         this.response = response;
108         this.requestContext = requestContext; 
109         this.window = window;
110         this.portletContent = portletContent; 
111         ((MutablePortletEntity)window.getPortletEntity()).setFragment(fragment);
112         this.expirationCache = expirationCache;
113         this.contentIsCached = contentIsCached;
114     }
115 
116     public RenderingJobImpl(PortletContainer container, 
117                             PortletRenderer renderer,
118                             PortletDefinition portletDefinition,
119                             PortletContent portletContent, 
120                             ContentFragment fragment,
121                             ContentDispatcherCtrl dispatcher,
122                             HttpServletRequest request, 
123                             HttpServletResponse response, 
124                             RequestContext requestContext, 
125                             PortletWindow window,
126                             PortalStatistics statistics,
127                             int expirationCache,
128                             boolean contentIsCached,
129                             Map workerAttributes)
130     {
131         this(container, renderer, portletDefinition, portletContent, fragment, dispatcher,
132                         request, response, requestContext, window, statistics, expirationCache, contentIsCached);
133         this.workerAttributes = workerAttributes;
134     }
135 
136     /***
137      * Sets portlet timout in milliseconds.
138      */
139     public void setTimeout(long timeout) {
140         this.timeout = timeout;
141     }
142 
143     /***
144      * Gets portlet timout in milliseconds.
145      */
146     public long getTimeout() {
147         return this.timeout;
148     }
149 
150     /***
151      * Checks if the portlet rendering is timeout
152      */
153     public boolean isTimeout() {
154         if ((this.timeout > 0) && (this.startTimeMillis > 0)) {
155             return (System.currentTimeMillis() - this.startTimeMillis > this.timeout);
156         }
157 
158         return false;
159     }
160 
161     /***
162      * Checks if queue is empty, if not try to empty it by calling
163      * the WorkerMonitor. When done, pause until next scheduled scan.
164      */
165     public void run()
166     {       
167         try
168         {
169             if (this.timeout > 0) {
170                 this.startTimeMillis = System.currentTimeMillis();
171             }
172 
173             // A little baby hack to make sure the worker thread has PortletContent to write too.
174             fragment.setPortletContent(portletContent);
175             execute();                     
176         }
177         finally
178         {
179             
180             synchronized (portletContent)
181             {
182                log.debug("Notifying completion of rendering job for fragment " + fragment.getId());                
183                portletContent.notifyAll();
184             }
185         }
186     }
187     
188     /***
189      * <p>
190      * execute
191      * </p>
192      *
193      * 
194      */
195     public void execute()
196     {
197         long start = System.currentTimeMillis();
198         boolean isParallelMode = false;
199         PortletWindow curWindow = this.window;
200         try
201         {
202             log.debug("Rendering OID "+this.window.getId()+" "+ this.request +" "+this.response);
203 
204             // if the current thread is worker, then store attribues in that.
205             if (this.workerAttributes != null)
206             {
207                 isParallelMode = (Thread.currentThread() instanceof Worker || CurrentWorkerContext.getCurrentWorkerContextUsed());                
208                 if (isParallelMode)
209                 {
210                     Iterator itAttrNames = this.workerAttributes.keySet().iterator();
211                     while (itAttrNames.hasNext()) 
212                     {
213                         String name = (String) itAttrNames.next();
214                         CurrentWorkerContext.setAttribute(name, this.workerAttributes.get(name));
215                     }
216                     
217                     // The portletEntity stores its portletDefinition into the ThreadLocal member,
218                     // before the worker starts doing a rendering job.
219                     // So the thread contexts are different from each other.
220                     // Therefore, in parallel mode, we have to clear threadlocal fragmentPortletDefinition cache
221                     // of portletEntity and to replace the portletDefinition with one of current worker context.
222                     // Refer to org.apache.jetspeed.components.portletentity.PortletEntityImpl class
223                     
224                     curWindow = (PortletWindow) 
225                         CurrentWorkerContext.getAttribute(PortalReservedParameters.PORTLET_WINDOW_ATTRIBUTE); 
226                     PortletEntityImpl curEntity = (PortletEntityImpl) curWindow.getPortletEntity();
227                     PortletDefinition oldPortletDefinition = curEntity.getPortletDefinition();
228                     PortletDefinition curPortletDefinition = (PortletDefinition)
229                         CurrentWorkerContext.getAttribute(PortalReservedParameters.PORTLET_DEFINITION_ATTRIBUTE);
230                     
231                     if (!oldPortletDefinition.getId().equals(curPortletDefinition.getId())) {
232                         curEntity.setPortletDefinition(curPortletDefinition);
233                     }
234                 }
235             }
236             
237             this.request.setAttribute(PortalReservedParameters.FRAGMENT_ATTRIBUTE, fragment);
238             this.request.setAttribute(PortalReservedParameters.PAGE_ATTRIBUTE, requestContext.getPage());
239             this.request.setAttribute(PortalReservedParameters.REQUEST_CONTEXT_ATTRIBUTE, requestContext);
240             this.request.setAttribute(PortalReservedParameters.REQUEST_CONTEXT_OBJECTS, requestContext.getObjects());            
241           //  this.request.setAttribute(PortalReservedParameters.CONTENT_DISPATCHER_ATTRIBUTE,dispatcher);
242             container.renderPortlet(this.window, this.request, this.response);               
243             this.response.flushBuffer();                           
244         }
245         catch (Throwable t)
246         {
247             if (t instanceof UnavailableException)
248             {
249                 // no need to dump a full stack trace to the log
250                 log.error("Error rendering portlet OID " + curWindow.getId() + ": " + t.toString());
251             }
252             else
253             {
254                 log.error("Error rendering portlet OID " + curWindow.getId(), t);
255             }
256             fragment.overrideRenderedContent(t.getMessage());
257         }
258         finally
259         {
260             long end = System.currentTimeMillis();            
261             boolean exceededTimeout = portletTracking.exceededTimeout(end - start, window);
262             if (fragment.getOverriddenContent() != null)
263                 portletContent.completeWithError();
264             else
265                 portletContent.complete();
266             
267             if (isParallelMode)
268             {
269                 this.renderer.addTitleToHeader(curWindow, fragment,
270                                                this.request, this.response,
271                                                this.dispatcher, this.contentIsCached);
272             
273                 CurrentWorkerContext.removeAllAttributes();
274             }
275             
276             if (fragment.getType().equals(ContentFragment.PORTLET))
277             {
278                 if (statistics != null)
279                 {
280                     statistics.logPortletAccess(requestContext, fragment.getName(), PortalStatistics.HTTP_OK, end - start);
281                 }
282                 if (exceededTimeout)
283                 {
284                     // took too long to render
285                     log.info("Portlet Exceeded timeout: " + curWindow.getPortletEntity().getPortletDefinition().getName() + " for window " + curWindow.getId());
286                     portletTracking.incrementRenderTimeoutCount(curWindow);
287                 }
288                 else
289                 {
290                     portletTracking.success(curWindow);
291                 }
292             }
293         }
294     }
295  
296     /***
297      * 
298      * <p>
299      * getWindow
300      * </p>
301      *
302      * @return The window this job is in charge of rendering
303      */
304     public PortletWindow getWindow()
305     {
306         return window;
307     }
308 
309     /***
310      * 
311      * <p>
312      * getPortletContent
313      * </p>
314      *
315      * @return The portlet content this job is in charge of rendering
316      */
317     public PortletContent getPortletContent()
318     {
319         return portletContent;
320     }
321 
322     public PortletDefinition getPortletDefinition()
323     {
324         return this.portletDefinition;
325     }
326 
327     public HttpServletRequest getRequest()
328     {
329         return this.request;
330     }
331 
332     public HttpServletResponse getResponse()
333     {
334         return this.response;
335     }
336 
337     public ContentFragment getFragment()
338     {
339         return this.fragment;
340     }
341 
342     public RequestContext getRequestContext()
343     {
344         return this.requestContext;
345     }
346 
347     public int getExpirationCache()
348     {
349         return this.expirationCache;
350     }
351 
352     public ContentDispatcherCtrl getDispatcher()
353     {
354         return this.dispatcher;
355     }
356 
357     public boolean isContentCached() {
358         return this.contentIsCached;
359     }
360 }