001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.jetspeed.aggregator.impl;
018:
019: import java.io.IOException;
020: import java.util.ArrayList;
021: import java.util.Iterator;
022: import java.util.List;
023:
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026: import org.apache.jetspeed.PortalReservedParameters;
027: import org.apache.jetspeed.aggregator.FailedToRenderFragmentException;
028: import org.apache.jetspeed.aggregator.PageAggregator;
029: import org.apache.jetspeed.aggregator.PortletContent;
030: import org.apache.jetspeed.aggregator.PortletRenderer;
031: import org.apache.jetspeed.aggregator.RenderingJob;
032: import org.apache.jetspeed.aggregator.CurrentWorkerContext;
033: import org.apache.jetspeed.container.state.NavigationalState;
034: import org.apache.jetspeed.exception.JetspeedException;
035: import org.apache.jetspeed.om.page.ContentFragment;
036: import org.apache.jetspeed.om.page.ContentPage;
037: import org.apache.jetspeed.request.RequestContext;
038: import org.apache.pluto.om.window.PortletWindow;
039:
040: /**
041: * Asynchronous Page Aggregator builds the content required to render a
042: * page of portlets by rendering the portlets in parallel. Each portlet is
043: * rendered on its own thread. A work manager handles the thread pooling
044: * and synchronization of worker threads.
045: *
046: * @author <a href="mailto:taylor@apache.org">David Sean Taylor </a>
047: * @author <a>Woonsan Ko</a>
048: * @version $Id: $
049: */
050: public class AsyncPageAggregatorImpl implements PageAggregator {
051: protected final static Log log = LogFactory
052: .getLog(AsyncPageAggregatorImpl.class);
053:
054: protected PortletRenderer renderer;
055:
056: protected List fallBackContentPathes;
057:
058: public AsyncPageAggregatorImpl(PortletRenderer renderer) {
059: this .renderer = renderer;
060: }
061:
062: /**
063: * Builds the portlet set defined in the context into a portlet tree.
064: *
065: * @return Unique Portlet Entity ID
066: */
067: public void build(RequestContext context) throws JetspeedException,
068: IOException {
069: ContentPage page = context.getPage();
070: if (null == page) {
071: throw new JetspeedException(
072: "Failed to find PSML Pin ContentPageAggregator.build");
073: }
074: ContentFragment root = page.getRootContentFragment();
075: if (root == null) {
076: throw new JetspeedException(
077: "No root ContentFragment found in ContentPage");
078: }
079: // handle maximized state
080: NavigationalState nav = context.getPortalURL()
081: .getNavigationalState();
082: PortletWindow window = nav.getMaximizedWindow();
083: if (null != window) {
084: renderMaximizedWindow(context, page, root, window);
085: } else {
086: aggregateAndRender(root, context, page, true, null, null,
087: null);
088: }
089: //dispatcher.include(root);
090: context.getResponse().getWriter().write(
091: root.getRenderedContent());
092: if (null != window) {
093: context
094: .getRequest()
095: .removeAttribute(
096: PortalReservedParameters.MAXIMIZED_FRAGMENT_ATTRIBUTE);
097: context
098: .getRequest()
099: .removeAttribute(
100: PortalReservedParameters.MAXIMIZED_LAYOUT_ATTRIBUTE);
101: }
102: }
103:
104: /**
105: * <p>
106: * renderMaximizedWindow
107: * </p>
108: *
109: * @param context
110: * @param page
111: * @param layoutContentFragment
112: * @param defaultPortletDecorator
113: * @param dispatcher
114: * @param window
115: * @throws FailedToRenderContentFragmentException
116: */
117: protected void renderMaximizedWindow(RequestContext context,
118: ContentPage page, ContentFragment layoutContentFragment,
119: PortletWindow window)
120: throws FailedToRenderFragmentException {
121: ContentFragment maxedContentFragment = page
122: .getContentFragmentById(window.getId().toString());
123: if (maxedContentFragment != null) {
124: context
125: .getRequest()
126: .setAttribute(
127: PortalReservedParameters.MAXIMIZED_FRAGMENT_ATTRIBUTE,
128: maxedContentFragment);
129: context.getRequest().setAttribute(
130: PortalReservedParameters.FRAGMENT_ATTRIBUTE,
131: maxedContentFragment);
132: context
133: .getRequest()
134: .setAttribute(
135: PortalReservedParameters.MAXIMIZED_LAYOUT_ATTRIBUTE,
136: page.getRootContentFragment());
137: try {
138: renderer.renderNow(maxedContentFragment, context);
139: renderer.renderNow(layoutContentFragment, context);
140: } catch (Exception e) {
141: log.error(e.getMessage(), e);
142: maxedContentFragment
143: .overrideRenderedContent("Sorry, but we were unable access the requested portlet. Send the following message to your portal admin: "
144: + e.getMessage());
145: }
146: }
147: }
148:
149: protected void aggregateAndRender(ContentFragment f,
150: RequestContext context, ContentPage page, boolean isRoot,
151: List sequentialJobs, List parallelJobs, List layoutFragments)
152: throws FailedToRenderFragmentException {
153: // First Pass, kick off async render threads for all portlets on page
154: // Store portlet rendering jobs in the list to wait later.
155: // Store layout fragment in the list to render later.
156: if (sequentialJobs == null) {
157: sequentialJobs = new ArrayList();
158: }
159: if (parallelJobs == null) {
160: parallelJobs = new ArrayList();
161: }
162: if (layoutFragments == null) {
163: layoutFragments = new ArrayList();
164: }
165:
166: if (f.getContentFragments() != null
167: && f.getContentFragments().size() > 0) {
168: Iterator children = f.getContentFragments().iterator();
169: while (children.hasNext()) {
170: ContentFragment child = (ContentFragment) children
171: .next();
172: if (!"hidden".equals(f.getState())) {
173: if (child.getType().equals(ContentFragment.PORTLET)) {
174: // create and store the portlet rendering job into the jobs lists.
175: RenderingJob job = renderer.createRenderingJob(
176: child, context);
177:
178: // The returned job can be null for some reason, such as invalid portlet entity.
179: if (job != null) {
180: if (job.getTimeout() > 0)
181: parallelJobs.add(job);
182: else
183: sequentialJobs.add(job);
184: }
185: } else {
186: // walk thru layout
187: // and store the layout rendering job into the layout jobs list.
188: aggregateAndRender(child, context, page, false,
189: sequentialJobs, parallelJobs,
190: layoutFragments);
191: layoutFragments.add(child);
192: }
193: }
194: }
195: }
196:
197: // If the fragment is not root, skip the following.
198: if (!isRoot)
199: return;
200:
201: int parallelJobCount = parallelJobs.size();
202: int sequentialJobCount = sequentialJobs.size();
203:
204: if (log.isInfoEnabled()) {
205: log.info("Aggregating " + page.getPath() + ". Parallel: "
206: + parallelJobCount + ", Sequential: "
207: + sequentialJobCount);
208: }
209:
210: CurrentWorkerContext
211: .setParallelRenderingMode(parallelJobCount > 0);
212:
213: // kick off the parallel rendering jobs
214: Iterator iter = parallelJobs.iterator();
215: while (iter.hasNext()) {
216: RenderingJob job = (RenderingJob) iter.next();
217: renderer.processRenderingJob(job);
218: }
219:
220: // kick off the sequential rendering jobs
221: iter = sequentialJobs.iterator();
222: while (iter.hasNext()) {
223: RenderingJob job = (RenderingJob) iter.next();
224: renderer.processRenderingJob(job);
225: }
226:
227: // synchronize on completion of all jobs
228: renderer.waitForRenderingJobs(parallelJobs);
229:
230: // Now, restore it to non parallel mode for rendering layout portlets.
231: CurrentWorkerContext.setParallelRenderingMode(false);
232:
233: // render layout fragments.
234: iter = layoutFragments.iterator();
235: while (iter.hasNext()) {
236: ContentFragment child = (ContentFragment) iter.next();
237: renderer.renderNow(child, context);
238: }
239:
240: // Start the actual rendering process
241: String defaultPortletDecorator = page
242: .getEffectiveDefaultDecorator(ContentFragment.PORTLET);
243: if (log.isDebugEnabled()) {
244: log.debug("Rendering portlet fragment: [[name, "
245: + f.getName() + "], [id, " + f.getId() + "]]");
246: }
247:
248: renderer.renderNow(f, context);
249: }
250:
251: }
|