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