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  package org.apache.jetspeed.aggregator.impl;
18  
19  import java.util.Collection;
20  import java.util.HashMap;
21  import java.util.Iterator;
22  import java.util.Map;
23  
24  import javax.servlet.http.HttpServletRequest;
25  import javax.servlet.http.HttpServletResponse;
26  
27  import org.apache.commons.lang.StringEscapeUtils;
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.jetspeed.JetspeedActions;
31  import org.apache.jetspeed.PortalReservedParameters;
32  import org.apache.jetspeed.aggregator.ContentDispatcher;
33  import org.apache.jetspeed.aggregator.ContentDispatcherCtrl;
34  import org.apache.jetspeed.aggregator.FailedToRenderFragmentException;
35  import org.apache.jetspeed.aggregator.PortletAccessDeniedException;
36  import org.apache.jetspeed.aggregator.PortletContent;
37  import org.apache.jetspeed.aggregator.PortletRenderer;
38  import org.apache.jetspeed.aggregator.PortletTrackingManager;
39  import org.apache.jetspeed.aggregator.RenderingJob;
40  import org.apache.jetspeed.aggregator.UnknownPortletDefinitionException;
41  import org.apache.jetspeed.aggregator.WorkerMonitor;
42  import org.apache.jetspeed.cache.CacheElement;
43  import org.apache.jetspeed.cache.ContentCacheKey;
44  import org.apache.jetspeed.cache.JetspeedCache;
45  import org.apache.jetspeed.components.portletentity.PortletEntityNotStoredException;
46  import org.apache.jetspeed.container.window.FailedToRetrievePortletWindow;
47  import org.apache.jetspeed.container.window.PortletWindowAccessor;
48  import org.apache.jetspeed.om.common.LocalizedField;
49  import org.apache.jetspeed.om.common.portlet.MutablePortletEntity;
50  import org.apache.jetspeed.om.common.portlet.PortletDefinitionComposite;
51  import org.apache.jetspeed.om.page.ContentFragment;
52  import org.apache.jetspeed.request.RequestContext;
53  import org.apache.jetspeed.security.SecurityAccessController;
54  import org.apache.jetspeed.services.title.DynamicTitleService;
55  import org.apache.jetspeed.statistics.PortalStatistics;
56  import org.apache.pluto.PortletContainer;
57  import org.apache.pluto.om.entity.PortletEntity;
58  import org.apache.pluto.om.window.PortletWindow;
59  
60  /***
61   * <h4>PortletRendererService <br />
62   * Jetspeed-2 Rendering service.</h4>
63   * <p>
64   * This service process all portlet rendering requests and interfaces with the
65   * portlet container to generate the resulting markup
66   * </p>
67   * 
68   * @author <a href="mailto:raphael@apache.org">Rapha?l Luta </a>
69   * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
70   * @author <a>Woonsan Ko</a>
71   * @version $Id: PortletRendererImpl.java,v 1.30 2005/05/20 14:54:22 ate Exp $
72   */
73  public class PortletRendererImpl implements PortletRenderer
74  {
75      protected final static Log log = LogFactory.getLog(PortletRendererImpl.class);
76  
77      protected WorkerMonitor workMonitor;
78      protected PortletContainer container;
79      protected PortletWindowAccessor windowAccessor;
80      protected PortalStatistics statistics;
81      protected DynamicTitleService addTitleService;
82  
83      protected PortletTrackingManager portletTracking;
84      
85      /***
86       *  flag indicating whether to check jetspeed-portlet.xml security constraints 
87       *  before rendering a portlet. If security check fails, do not display portlet content
88       */
89      protected boolean checkSecurityConstraints;   
90      /***
91       * For security constraint checks
92       */
93      protected SecurityAccessController accessController;
94      
95      /***
96       * JSR 168 Portlet Content Cache
97       */
98      protected JetspeedCache portletContentCache;
99      
100     /***
101      * OutOfService Cache
102      */
103     protected boolean overrideTitles = false;
104     public static final String OUT_OF_SERVICE_MESSAGE = "Portlet is not responding and has been taken out of service.";
105     
106     public PortletRendererImpl(PortletContainer container, 
107                                PortletWindowAccessor windowAccessor,
108                                WorkerMonitor workMonitor,
109                                PortalStatistics statistics,
110                                DynamicTitleService addTitleService,
111                                PortletTrackingManager portletTracking,
112                                boolean checkSecurityConstraints,
113                                SecurityAccessController accessController,
114                                JetspeedCache portletContentCache,
115                                boolean overrideTitles)
116     {
117         this.container = container;
118         this.windowAccessor = windowAccessor;
119         this.workMonitor = workMonitor;
120         this.statistics = statistics;
121         this.addTitleService = addTitleService;
122         this.portletTracking = portletTracking;
123         this.checkSecurityConstraints = checkSecurityConstraints;
124         this.accessController = accessController;
125         this.portletContentCache = portletContentCache;
126         this.overrideTitles = overrideTitles;
127     }
128 
129     public PortletRendererImpl(PortletContainer container, 
130             PortletWindowAccessor windowAccessor,
131             WorkerMonitor workMonitor,
132             PortalStatistics statistics,
133             DynamicTitleService addTitleService,
134             PortletTrackingManager portletTracking,
135             boolean checkSecurityConstraints,
136             SecurityAccessController accessController,
137             JetspeedCache portletContentCache)
138     {
139         this(container, windowAccessor, workMonitor, statistics, 
140              addTitleService, portletTracking, checkSecurityConstraints,
141              accessController, portletContentCache, false);
142     }
143     
144     public PortletRendererImpl(PortletContainer container, 
145                                PortletWindowAccessor windowAccessor,
146                                WorkerMonitor workMonitor,
147                                PortalStatistics statistics,
148                                DynamicTitleService addTitleService)
149     {
150         this(container, windowAccessor, workMonitor, statistics, null, null, false, null, null, true);
151     }
152 
153     public PortletRendererImpl(PortletContainer container, 
154                                PortletWindowAccessor windowAccessor,
155                                WorkerMonitor workMonitor,
156                                PortalStatistics statistics)
157     {
158         this( container, windowAccessor, workMonitor, statistics, null );
159     }
160     
161     public PortletRendererImpl(PortletContainer container, 
162                                PortletWindowAccessor windowAccessor,
163                                WorkerMonitor workMonitor)
164     {
165         this( container, windowAccessor, workMonitor, null );
166     }
167     
168     public void start()
169     {
170         // workMonitor.start();
171     }
172 
173     public void stop()
174     {
175         // this.monitor.shutdown ?
176     }
177 
178     /***
179      * Render the specified Page fragment. Result is returned in the
180      * PortletResponse.
181      * 
182      * @throws FailedToRenderFragmentException
183      * @throws FailedToRetrievePortletWindow
184      * @throws UnknownPortletDefinitionException
185      */
186     public void renderNow( ContentFragment fragment, RequestContext requestContext )
187     {
188         HttpServletRequest servletRequest =null;
189         HttpServletResponse servletResponse = null;
190         ContentDispatcherCtrl dispatcher = null;    
191         boolean contentIsCached = false;
192         try
193         {
194             PortletWindow portletWindow = getPortletWindow(fragment);
195             PortletDefinitionComposite portletDefinition = 
196                 (PortletDefinitionComposite) portletWindow.getPortletEntity().getPortletDefinition();           
197             if (checkSecurityConstraints && !checkSecurityConstraint(portletDefinition, fragment))
198             {
199                 throw new PortletAccessDeniedException("Access Denied.");
200             }
201             if (portletTracking.isOutOfService(portletWindow))
202             {
203                 log.info("Taking portlet out of service: " + portletDefinition.getUniqueName() + " for window " + fragment.getId());
204                 fragment.overrideRenderedContent(OUT_OF_SERVICE_MESSAGE);
205                 return;
206             }
207             long timeoutMetadata = this.getTimeoutOnJob(portletDefinition);
208             portletTracking.setExpiration(portletWindow, timeoutMetadata);            
209             int expirationCache = getExpirationCache(portletDefinition);
210             if (expirationCache != 0)
211             {
212                 if (retrieveCachedContent(requestContext, fragment, portletWindow, expirationCache, portletDefinition))
213                     return;
214                 contentIsCached = true;
215             }
216             if (dispatcher == null)
217             {
218                 dispatcher = createDispatcher(requestContext, fragment, expirationCache);
219             }
220             servletRequest = requestContext.getRequestForWindow(portletWindow);
221             servletResponse = dispatcher.getResponseForWindow(portletWindow, requestContext);
222             RenderingJob rJob = 
223                 buildRenderingJob(portletWindow, fragment, servletRequest, servletResponse,
224                                   requestContext, false, portletDefinition, dispatcher, null, 
225                                   expirationCache, contentIsCached, timeoutMetadata);
226             rJob.execute();
227             addTitleToHeader( portletWindow, fragment, servletRequest, servletResponse, dispatcher, contentIsCached);
228         }
229         catch (PortletAccessDeniedException e)
230         {
231             fragment.overrideRenderedContent(e.getLocalizedMessage());                        
232         }        
233         catch (Exception e)
234         {
235             fragment.overrideRenderedContent(e.getLocalizedMessage());
236             log.error(e.toString(), e);
237         }
238     }
239 
240     /***
241      * Render the specified Page fragment. Result is returned in the
242      * PortletResponse.
243      * 
244      * @throws FailedToRenderFragmentException
245      * @throws FailedToRetrievePortletWindow
246      * @throws UnknownPortletDefinitionException
247      * @throws PortletAccessDeniedException
248      */
249     public void renderNow( ContentFragment fragment, HttpServletRequest request, HttpServletResponse response )          
250     {
251         RequestContext requestContext = (RequestContext) request
252                 .getAttribute(PortalReservedParameters.REQUEST_CONTEXT_ATTRIBUTE);
253         renderNow(fragment, requestContext);
254     }
255     
256     protected int getExpirationCache(PortletDefinitionComposite portletDefinition)
257     {
258         if (portletDefinition == null)
259             return 0;
260         String expiration = portletDefinition.getExpirationCache();
261         if (expiration == null)
262             return 0;
263         return Integer.parseInt(expiration);
264     }
265     
266     /***
267      * Render the specified Page fragment. The method returns before rendering
268      * is complete, rendered content can be accessed through the Content Dispatcher
269      * 
270      * @return the asynchronous portlet rendering job to synchronize
271      */
272     public RenderingJob render( ContentFragment fragment, RequestContext requestContext )
273     {
274         RenderingJob job = null;
275 
276         try
277         {
278             job = createRenderingJob(fragment, requestContext);
279         }
280         catch (Exception e)
281         {
282             log.error("render() failed: " + e.toString(), e);
283             fragment.overrideRenderedContent(e.getLocalizedMessage());            
284         }
285 
286         if (job != null)
287         {
288             processRenderingJob(job, true);
289         }
290 
291         return job;
292     }       
293     
294     /*** 
295      * 
296      * Create a rendering job for the specified Page fragment.
297      * The method returns a rendering job which should be passed to 'processRenderingJob(RenderingJob job)' method.
298      * @return portlet rendering job to pass to render(RenderingJob job) method
299      * @throws FailedToRetrievePortletWindow
300      * @throws UnknownPortletDefinitionException
301      * @throws PortletAccessDeniedException
302      */
303     public RenderingJob createRenderingJob(ContentFragment fragment, RequestContext requestContext)
304     {
305         RenderingJob job = null;
306         boolean contentIsCached = false;       
307         try
308         {
309             PortletWindow portletWindow = getPortletWindow(fragment);
310             PortletDefinitionComposite portletDefinition = 
311                 (PortletDefinitionComposite) portletWindow.getPortletEntity().getPortletDefinition();     
312 
313             long timeoutMetadata = this.getTimeoutOnJob(portletDefinition);
314             portletTracking.setExpiration(portletWindow, timeoutMetadata);            
315             
316             if (checkSecurityConstraints && !checkSecurityConstraint(portletDefinition, fragment))
317             {
318                 throw new PortletAccessDeniedException("Access Denied.");
319             }
320             if (portletTracking.isOutOfService(portletWindow))
321             {
322                 fragment.overrideRenderedContent(OUT_OF_SERVICE_MESSAGE);
323                 return null;
324             }
325             int expirationCache = getExpirationCache(portletDefinition);
326             if (expirationCache != 0)
327             {
328                 portletTracking.setExpiration(portletWindow, expirationCache);
329                 contentIsCached = retrieveCachedContent(requestContext, fragment, portletWindow, 
330                                                         expirationCache, portletDefinition);
331                 if (contentIsCached)
332                 {
333                     return null;
334                 }
335             }
336             job = buildRenderingJob( portletWindow, fragment, requestContext, true, 
337                                      portletDefinition, null, contentIsCached, timeoutMetadata );
338         }
339         catch (Exception e)
340         {
341             throw new RuntimeException("Failed to create rendering job", e);
342         }
343 
344         return job;
345     }
346            
347     /*** 
348      * 
349      * Render the specified rendering job.
350      * The method returns before rendering is complete when the job is processed in parallel mode.
351      * When it is not parallel mode, it returns after rendering is complete.
352      * @throws FailedToRenderFragmentException
353      */
354     public void processRenderingJob(RenderingJob job)
355     {
356         processRenderingJob(job, false);
357     }
358 
359     protected void processRenderingJob(RenderingJob job, boolean parallelOnly)
360     {
361         ContentFragment fragment = null;
362 
363         try
364         {
365             if (parallelOnly || job.getTimeout() > 0)
366             {
367                 workMonitor.process(job);
368             }
369             else
370             {
371                 job.execute();
372                 addTitleToHeader(job.getWindow(), job.getFragment(), 
373                                  job.getRequest(), job.getResponse(), job.getDispatcher(), 
374                                  job.isContentCached());                
375             }
376         }
377         catch (Exception e1)
378         {
379             log.error("render() failed: " + e1.toString(), e1);
380             fragment.overrideRenderedContent(e1.getLocalizedMessage());            
381         }
382     }
383 
384     /***
385      * Retrieve cached content, if content retrieved successfully return true, if no content found return false
386      * @param requestContext
387      * @param fragment
388      * @param portletWindow
389      * @return true when content found, otherwise false
390      */
391     protected boolean retrieveCachedContent(RequestContext requestContext, ContentFragment fragment, 
392                                             PortletWindow portletWindow, int expiration, 
393                                             PortletDefinitionComposite portletDefinition)
394         throws Exception
395     {
396         ContentCacheKey cacheKey = portletContentCache.createCacheKey(requestContext, fragment.getId());        
397         CacheElement cachedElement = portletContentCache.get(cacheKey);
398         if (cachedElement != null)
399         {
400             PortletContent portletContent = (PortletContent)cachedElement.getContent();            
401             fragment.setPortletContent(portletContent);
402             ContentDispatcherCtrl dispatcher = new ContentDispatcherImpl(portletContent);
403             HttpServletRequest servletRequest = requestContext.getRequestForWindow(portletWindow);
404 
405             this.addTitleService.setDynamicTitle(portletWindow, servletRequest, dispatcher.getPortletContent(fragment).getTitle());
406             return true;
407         }        
408         return false;
409     }
410     
411     public ContentDispatcherCtrl createDispatcher(RequestContext request, ContentFragment fragment, int expirationCache)
412     {
413         ContentCacheKey cacheKey = portletContentCache.createCacheKey(request, fragment.getId());                
414         PortletContent content = new PortletContentImpl(this, cacheKey, expirationCache);
415         ContentDispatcherCtrl dispatcher = new ContentDispatcherImpl(content); 
416         return dispatcher;
417     }
418     
419     /***
420      * Retrieve the ContentDispatcher for the specified request
421      */
422     public ContentDispatcher getDispatcher( RequestContext request, boolean isParallel )
423     {
424         return request.getContentDispatcher();
425     }
426 
427 
428     protected PortletWindow getPortletWindow( ContentFragment fragment ) throws FailedToRetrievePortletWindow, PortletEntityNotStoredException
429     {
430         // ObjectID oid = JetspeedObjectID.createFromString(fragment.getId());
431         PortletWindow portletWindow = windowAccessor.getPortletWindow(fragment);
432 
433         if (portletWindow == null)
434         {
435             throw new FailedToRetrievePortletWindow("Portlet Window creation failed for fragment: "
436                                                     + fragment.getId() + ", " + fragment.getName());
437         }
438 
439         PortletEntity portletEntity = portletWindow.getPortletEntity();
440         ((MutablePortletEntity)portletEntity).setFragment(fragment);
441 
442         return portletWindow;
443     }
444     
445     protected RenderingJob buildRenderingJob( PortletWindow portletWindow, ContentFragment fragment, 
446                                               RequestContext requestContext, boolean isParallel,
447                                               PortletDefinitionComposite portletDefinition, 
448                                               PortletContent portletContent, boolean contentIsCached, long timeoutMetadata)
449         throws PortletAccessDeniedException, FailedToRetrievePortletWindow, PortletEntityNotStoredException        
450     {
451         int expirationCache = getExpirationCache(portletDefinition);
452         ContentDispatcherCtrl dispatcher = createDispatcher(requestContext, fragment, expirationCache);
453         HttpServletRequest request = requestContext.getRequestForWindow(portletWindow);
454         HttpServletResponse response = dispatcher.getResponseForWindow(portletWindow, requestContext);
455 
456         return buildRenderingJob( portletWindow, fragment, request, response,
457                                   requestContext, isParallel,
458                                   portletDefinition, dispatcher,
459                                   portletContent, expirationCache, contentIsCached, timeoutMetadata );        
460     }
461 
462     protected RenderingJob buildRenderingJob( PortletWindow portletWindow, ContentFragment fragment, 
463                                               HttpServletRequest request, HttpServletResponse response, 
464                                               RequestContext requestContext, boolean isParallel,
465                                               PortletDefinitionComposite portletDefinition, 
466                                               ContentDispatcherCtrl dispatcher, 
467                                               PortletContent portletContent, 
468                                               int expirationCache, boolean contentIsCached, long timeoutMetadata)
469              throws PortletAccessDeniedException, FailedToRetrievePortletWindow, PortletEntityNotStoredException
470    {    
471         RenderingJob rJob = null;
472                
473         request.setAttribute(PortalReservedParameters.PAGE_ATTRIBUTE, requestContext.getPage());
474         request.setAttribute(PortalReservedParameters.FRAGMENT_ATTRIBUTE, fragment);
475         request.setAttribute(PortalReservedParameters.CONTENT_DISPATCHER_ATTRIBUTE, dispatcher);
476         request.setAttribute(PortalReservedParameters.REQUEST_CONTEXT_ATTRIBUTE, requestContext);
477         request.setAttribute(PortalReservedParameters.REQUEST_CONTEXT_OBJECTS, requestContext.getObjects());                        
478         request.setAttribute(PortalReservedParameters.PATH_ATTRIBUTE, requestContext.getAttribute(PortalReservedParameters.PATH_ATTRIBUTE));
479         request.setAttribute(PortalReservedParameters.PORTLET_WINDOW_ATTRIBUTE, portletWindow);
480         
481         if (portletContent == null)
482         {
483             portletContent = dispatcher.getPortletContent(fragment);
484             fragment.setPortletContent(portletContent);
485         }
486         // In case of parallel mode, store attributes in a map to be refered by worker.
487         if (isParallel)
488         {
489             Map workerAttrs = new HashMap();
490             workerAttrs.put(PortalReservedParameters.PAGE_ATTRIBUTE, requestContext.getPage());
491             workerAttrs.put(PortalReservedParameters.FRAGMENT_ATTRIBUTE, fragment);
492             workerAttrs.put(PortalReservedParameters.CONTENT_DISPATCHER_ATTRIBUTE, dispatcher);
493             workerAttrs.put(PortalReservedParameters.REQUEST_CONTEXT_ATTRIBUTE, requestContext);
494             workerAttrs.put(PortalReservedParameters.REQUEST_CONTEXT_OBJECTS, requestContext.getObjects());                                    
495             workerAttrs.put(PortalReservedParameters.PATH_ATTRIBUTE, requestContext.getAttribute(PortalReservedParameters.PATH_ATTRIBUTE));
496             workerAttrs.put(PortalReservedParameters.PORTLET_WINDOW_ATTRIBUTE, portletWindow);
497 
498             // the portlet invoker is not thread safe; it stores current portlet definition as a member variable.
499             // so, store portlet definition as an attribute of worker
500             workerAttrs.put(PortalReservedParameters.PORTLET_DEFINITION_ATTRIBUTE, portletDefinition);
501 
502             rJob = new RenderingJobImpl(container, this, portletDefinition, portletContent, fragment, dispatcher,
503                                                     request, response, requestContext, portletWindow, 
504                                                     statistics, expirationCache, contentIsCached, workerAttrs);
505             
506         }
507         else
508         {
509             rJob = new RenderingJobImpl(container, this, portletDefinition, portletContent, fragment, dispatcher,
510                                                          request, response, requestContext, portletWindow, 
511                                                          statistics, expirationCache, contentIsCached );
512             
513         }
514         setTimeoutOnJob(timeoutMetadata, rJob);
515         return rJob;
516     }
517  
518     protected long getTimeoutOnJob(PortletDefinitionComposite portletDefinition)
519     {
520         long timeoutMetadata = 0;
521         Collection timeoutFields = null;
522 
523         if (portletDefinition != null)
524         {
525             timeoutFields = portletDefinition.getMetadata().getFields(PortalReservedParameters.PORTLET_EXTENDED_DESCRIPTOR_RENDER_TIMEOUT);
526         }
527 
528         if (timeoutFields != null) 
529         {
530             Iterator it = timeoutFields.iterator();
531 
532             if (it.hasNext()) 
533             {
534                 LocalizedField timeoutField = (LocalizedField) timeoutFields.iterator().next();
535 
536                 try 
537                 {
538                     timeoutMetadata = Long.parseLong(timeoutField.getValue());
539                 }
540                 catch (NumberFormatException nfe) 
541                 {
542                     log.warn("Invalid timeout metadata: " + nfe.getMessage());
543                 }
544             }
545         }       
546         return timeoutMetadata;
547     }
548     
549     protected void setTimeoutOnJob(long timeoutMetadata, RenderingJob rJob)
550     {
551         
552         if (timeoutMetadata > 0) 
553         {
554             rJob.setTimeout(timeoutMetadata);
555         }
556         else if (this.portletTracking.getDefaultPortletTimeout() > 0) 
557         {
558             rJob.setTimeout(this.portletTracking.getDefaultPortletTimeout());
559         }        
560     }
561     
562     public void addTitleToHeader( PortletWindow portletWindow, ContentFragment fragment, 
563                                   HttpServletRequest request, HttpServletResponse response, 
564                                   ContentDispatcherCtrl dispatcher, boolean isCacheTitle )
565     {
566         if (overrideTitles)
567         {
568             try
569             {
570                 String title = fragment.getTitle();
571 
572                 if ( title == null )
573                 {
574                     title = addTitleService.getDynamicTitle( portletWindow, request );
575                 }
576 
577                 response.setHeader( "JS_PORTLET_TITLE", StringEscapeUtils.escapeHtml( title ) );
578                 dispatcher.getPortletContent(fragment).setTitle(title);          
579             }
580             catch (Exception e)
581             {
582                 log.error("Unable to reteive portlet title: " + e.getMessage(), e);
583             }
584         }
585         else
586         {
587             String title = null;
588 
589             if (isCacheTitle)
590             {
591                 title = fragment.getTitle();
592 
593                 if ( title == null )
594                 {
595                     title = addTitleService.getDynamicTitle(portletWindow, request);
596                 }
597 
598                 dispatcher.getPortletContent(fragment).setTitle(title);
599             }
600 
601             if (title == null)
602             {
603                 title = addTitleService.getDynamicTitle(portletWindow, request);
604                 dispatcher.getPortletContent(fragment).setTitle(title);                
605             }
606         }
607     }
608     
609     protected boolean checkSecurityConstraint(PortletDefinitionComposite portlet, ContentFragment fragment)
610     {
611         if (fragment.getType().equals(ContentFragment.PORTLET))
612         {
613             if (accessController != null)
614             {
615                 return accessController.checkPortletAccess(portlet, JetspeedActions.MASK_VIEW);
616             }
617         }
618         return true;
619     }
620  
621     protected void addToCache(PortletContent content)
622     {
623         CacheElement cachedElement = portletContentCache.createElement(content.getCacheKey(), content);
624         if (content.getExpiration() == -1)
625         {
626             cachedElement.setTimeToIdleSeconds(portletContentCache.getTimeToIdleSeconds());
627             cachedElement.setTimeToLiveSeconds(portletContentCache.getTimeToLiveSeconds());
628         }
629         else
630         {       
631             cachedElement.setTimeToIdleSeconds(content.getExpiration());
632             cachedElement.setTimeToLiveSeconds(content.getExpiration());
633         }
634         portletContentCache.put(cachedElement);        
635     }    
636     
637     public void notifyContentComplete(PortletContent content)
638     {
639         if (content.getExpiration() != 0)
640             addToCache(content);
641     }
642     
643     public PortletTrackingManager getPortletTrackingManager()
644     {
645         return this.portletTracking;
646     }
647 }