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.io.IOException;
20  import java.util.ArrayList;
21  import java.util.Iterator;
22  import java.util.List;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.jetspeed.PortalReservedParameters;
27  import org.apache.jetspeed.aggregator.FailedToRenderFragmentException;
28  import org.apache.jetspeed.aggregator.PageAggregator;
29  import org.apache.jetspeed.aggregator.PortletContent;
30  import org.apache.jetspeed.aggregator.PortletRenderer;
31  import org.apache.jetspeed.aggregator.RenderingJob;
32  import org.apache.jetspeed.aggregator.CurrentWorkerContext;
33  import org.apache.jetspeed.container.state.NavigationalState;
34  import org.apache.jetspeed.exception.JetspeedException;
35  import org.apache.jetspeed.om.page.ContentFragment;
36  import org.apache.jetspeed.om.page.ContentPage;
37  import org.apache.jetspeed.request.RequestContext;
38  import org.apache.pluto.om.window.PortletWindow;
39  
40  /***
41   * Asynchronous Page Aggregator builds the content required to render a 
42   * page of portlets by rendering the portlets in parallel. Each portlet is
43   * rendered on its own thread. A work manager handles the thread pooling
44   * and synchronization of worker threads.
45   * 
46   * @author <a href="mailto:taylor@apache.org">David Sean Taylor </a>
47   * @author <a>Woonsan Ko</a>
48   * @version $Id: $
49   */
50  public class AsyncPageAggregatorImpl implements PageAggregator
51  {
52      protected final static Log log = LogFactory.getLog(AsyncPageAggregatorImpl.class);
53  
54      protected PortletRenderer renderer;
55  
56      protected List fallBackContentPathes;
57  
58      public AsyncPageAggregatorImpl(PortletRenderer renderer)
59      {
60          this.renderer = renderer;
61      }
62  
63      /***
64       * Builds the portlet set defined in the context into a portlet tree.
65       * 
66       * @return Unique Portlet Entity ID
67       */
68      public void build( RequestContext context ) throws JetspeedException, IOException
69      {
70          ContentPage page = context.getPage();
71          if (null == page)
72          {
73              throw new JetspeedException("Failed to find PSML Pin ContentPageAggregator.build");
74          }
75          ContentFragment root = page.getRootContentFragment();
76          if (root == null)
77          {
78              throw new JetspeedException("No root ContentFragment found in ContentPage");
79          }
80          // handle maximized state
81          NavigationalState nav = context.getPortalURL().getNavigationalState();
82          PortletWindow window = nav.getMaximizedWindow();
83          if (null != window)
84          {
85              renderMaximizedWindow(context, page, root, window);
86          }
87          else
88          {
89              aggregateAndRender(root, context, page, true, null, null, null);
90          }        
91          //dispatcher.include(root);
92          context.getResponse().getWriter().write(root.getRenderedContent());
93          if (null != window)
94          {
95              context.getRequest().removeAttribute(PortalReservedParameters.MAXIMIZED_FRAGMENT_ATTRIBUTE);
96              context.getRequest().removeAttribute(PortalReservedParameters.MAXIMIZED_LAYOUT_ATTRIBUTE);
97          }
98      }
99  
100     /***
101      * <p>
102      * renderMaximizedWindow
103      * </p>
104      * 
105      * @param context
106      * @param page
107      * @param layoutContentFragment
108      * @param defaultPortletDecorator
109      * @param dispatcher
110      * @param window
111      * @throws FailedToRenderContentFragmentException
112      */
113     protected void renderMaximizedWindow( RequestContext context, ContentPage page, ContentFragment layoutContentFragment,
114             PortletWindow window ) throws FailedToRenderFragmentException
115     {
116         ContentFragment maxedContentFragment = page.getContentFragmentById(window.getId().toString());
117         if (maxedContentFragment != null)
118         {
119             context.getRequest().setAttribute(PortalReservedParameters.MAXIMIZED_FRAGMENT_ATTRIBUTE, maxedContentFragment);
120             context.getRequest().setAttribute(PortalReservedParameters.FRAGMENT_ATTRIBUTE, maxedContentFragment);
121             context.getRequest().setAttribute(PortalReservedParameters.MAXIMIZED_LAYOUT_ATTRIBUTE, page.getRootContentFragment());
122             try
123             {
124                 renderer.renderNow(maxedContentFragment, context);
125                 renderer.renderNow(layoutContentFragment, context);                              
126             }
127             catch (Exception e)
128             {
129                 log.error(e.getMessage(), e);
130                 maxedContentFragment.overrideRenderedContent("Sorry, but we were unable access the requested portlet.  Send the following message to your portal admin:  "+  e.getMessage());
131             }
132         }
133     }
134 
135     protected void aggregateAndRender(ContentFragment f, RequestContext context, ContentPage page, boolean isRoot,
136                                       List sequentialJobs, List parallelJobs, List layoutFragments)
137             throws FailedToRenderFragmentException
138     {
139         // First Pass, kick off async render threads for all portlets on page 
140         // Store portlet rendering jobs in the list to wait later.
141         // Store layout fragment in the list to render later.
142         if (sequentialJobs == null) 
143         {
144             sequentialJobs = new ArrayList();
145         }
146         if (parallelJobs == null) 
147         {
148             parallelJobs = new ArrayList();
149         }        
150         if (layoutFragments == null)
151         {
152             layoutFragments = new ArrayList();
153         }
154 
155         if (f.getContentFragments() != null && f.getContentFragments().size() > 0)
156         {
157             Iterator children = f.getContentFragments().iterator();
158             while (children.hasNext())
159             {
160                 ContentFragment child = (ContentFragment) children.next();
161                 if (!"hidden".equals(f.getState()))
162                 {
163                     if (child.getType().equals(ContentFragment.PORTLET))
164                     {
165                         // create and store the portlet rendering job into the jobs lists.
166                         RenderingJob job = renderer.createRenderingJob(child, context);
167 
168                         // The returned job can be null for some reason, such as invalid portlet entity.
169                         if (job != null) 
170                         {
171                             if (job.getTimeout() > 0)
172                                 parallelJobs.add(job);
173                             else
174                                 sequentialJobs.add(job);
175                         }
176                     }
177                     else
178                     {
179                         // walk thru layout 
180                         // and store the layout rendering job into the layout jobs list.
181                         aggregateAndRender(child, context, page, false, sequentialJobs, parallelJobs, layoutFragments);
182                         layoutFragments.add(child);
183                     }
184                 }
185             }
186         }
187 
188         // If the fragment is not root, skip the following.
189         if (!isRoot)
190             return;
191         
192         int parallelJobCount = parallelJobs.size();
193         int sequentialJobCount = sequentialJobs.size();
194         
195         if (log.isInfoEnabled())
196         {
197             log.info("Aggregating " + page.getPath() + ". Parallel: " + parallelJobCount + ", Sequential: " + sequentialJobCount);
198         }
199         
200         CurrentWorkerContext.setParallelRenderingMode(parallelJobCount > 0);
201 
202         // kick off the parallel rendering jobs
203         Iterator iter = parallelJobs.iterator();
204         while (iter.hasNext())
205         {
206             RenderingJob job = (RenderingJob) iter.next();
207             renderer.processRenderingJob(job);
208         }
209 
210         // kick off the sequential rendering jobs
211         iter = sequentialJobs.iterator();
212         while (iter.hasNext())
213         {
214             RenderingJob job = (RenderingJob) iter.next();
215             renderer.processRenderingJob(job);
216         }
217 
218         // synchronize on completion of all jobs
219         renderer.waitForRenderingJobs(parallelJobs);
220         
221         // Now, restore it to non parallel mode for rendering layout portlets.
222         CurrentWorkerContext.setParallelRenderingMode(false);
223         
224         // render layout fragments.
225         iter = layoutFragments.iterator();
226         while (iter.hasNext()) 
227         {
228             ContentFragment child = (ContentFragment) iter.next();
229             renderer.renderNow(child, context);
230         }
231         
232         // Start the actual rendering process
233         String defaultPortletDecorator = page.getEffectiveDefaultDecorator(ContentFragment.PORTLET);
234         if (log.isDebugEnabled())
235         {
236             log.debug("Rendering portlet fragment: [[name, " + f.getName() + "], [id, " + f.getId() + "]]");
237         }        
238         
239         renderer.renderNow(f, context);
240     }
241     
242 
243 }