KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > apps > StreamRenderer


1 /*
2  * $Id: StreamRenderer.java,v 1.6.2.10 2003/02/25 10:18:32 jeremias Exp $
3  * ============================================================================
4  * The Apache Software License, Version 1.1
5  * ============================================================================
6  *
7  * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without modifica-
10  * tion, are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * 3. The end-user documentation included with the redistribution, if any, must
20  * include the following acknowledgment: "This product includes software
21  * developed by the Apache Software Foundation (http://www.apache.org/)."
22  * Alternately, this acknowledgment may appear in the software itself, if
23  * and wherever such third-party acknowledgments normally appear.
24  *
25  * 4. The names "FOP" and "Apache Software Foundation" must not be used to
26  * endorse or promote products derived from this software without prior
27  * written permission. For written permission, please contact
28  * apache@apache.org.
29  *
30  * 5. Products derived from this software may not be called "Apache", nor may
31  * "Apache" appear in their name, without prior written permission of the
32  * Apache Software Foundation.
33  *
34  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
35  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
36  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
37  * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
38  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
39  * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
40  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
41  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
43  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44  * ============================================================================
45  *
46  * This software consists of voluntary contributions made by many individuals
47  * on behalf of the Apache Software Foundation and was originally created by
48  * James Tauber <jtauber@jtauber.com>. For more information on the Apache
49  * Software Foundation, please see <http://www.apache.org/>.
50  */

51 package org.apache.fop.apps;
52
53 import java.io.OutputStream JavaDoc;
54 import java.io.IOException JavaDoc;
55 import java.util.ArrayList JavaDoc;
56 import java.util.Iterator JavaDoc;
57
58 import org.xml.sax.SAXException JavaDoc;
59
60 import org.apache.fop.datatypes.IDReferences;
61 import org.apache.fop.extensions.ExtensionObj;
62 import org.apache.fop.fo.flow.Marker;
63 import org.apache.fop.fo.pagination.PageSequence;
64 import org.apache.fop.layout.AreaTree;
65 import org.apache.fop.layout.FontInfo;
66 import org.apache.fop.layout.Page;
67 import org.apache.fop.render.Renderer;
68
69 import org.apache.avalon.framework.logger.Logger;
70
71 /**
72   This class acts as a bridge between the XML:FO parser
73   and the formatting/rendering classes. It will queue
74   PageSequences up until all the IDs required by them
75   are satisfied, at which time it will render the
76   pages.<P>
77
78   StreamRenderer is created by Driver and called from
79   FOTreeBuilder when a PageSequence is created,
80   and AreaTree when a Page is formatted.<P>
81 */

82 public class StreamRenderer {
83     private static final boolean MEM_PROFILE_WITH_GC = false;
84
85     /**
86       Somewhere to get our stats from.
87     */

88     private Runtime JavaDoc runtime = Runtime.getRuntime();
89
90     /**
91       Keep track of the number of pages rendered.
92     */

93     int pageCount = 0;
94
95     /**
96       Keep track of heap memory allocated,
97       for statistical purposes.
98     */

99     private long initialMemory;
100
101     /**
102       Keep track of time used by renderer.
103     */

104     private long startTime;
105
106     /**
107       The stream to which this rendering is to be
108       written to. <B>Note</B> that some renderers
109       do not render to a stream, and that this
110       member can therefore be null.
111     */

112     private OutputStream JavaDoc outputStream;
113
114     /**
115       The renderer being used.
116     */

117     private Renderer renderer;
118
119     /**
120      * The formatting results to be handed back to the caller.
121      */

122     private FormattingResults results = new FormattingResults();
123
124     /**
125       The FontInfo for this renderer.
126     */

127     private FontInfo fontInfo = new FontInfo();
128
129     /**
130       The list of pages waiting to be renderered.
131     */

132     private ArrayList JavaDoc renderQueue = new ArrayList JavaDoc();
133
134     /**
135       The current set of IDReferences, passed to the
136       areatrees and pages. This is used by the AreaTree
137       as a single map of all IDs.
138     */

139     private IDReferences idReferences = new IDReferences();
140
141     /**
142      * The list of extensions.
143      */

144     private ArrayList JavaDoc extensions = new ArrayList JavaDoc();
145
146     /**
147      * The list of markers.
148      */

149     private ArrayList JavaDoc documentMarkers;
150     private ArrayList JavaDoc currentPageSequenceMarkers;
151     private PageSequence currentPageSequence;
152     
153     private Logger log;
154
155     public StreamRenderer(OutputStream JavaDoc outputStream, Renderer renderer) {
156         this.outputStream = outputStream;
157         this.renderer = renderer;
158     }
159
160     public void setLogger(Logger logger) {
161         log = logger;
162     }
163
164     public IDReferences getIDReferences() {
165         return idReferences;
166     }
167
168     public FormattingResults getResults() {
169         return this.results;
170     }
171
172     public void addExtension(ExtensionObj ext) {
173         extensions.add(ext);
174     }
175
176     public void startRenderer()
177     throws SAXException JavaDoc {
178         pageCount = 0;
179
180         if (MEM_PROFILE_WITH_GC)
181             System.gc(); // This takes time but gives better results
182

183         initialMemory = runtime.totalMemory() - runtime.freeMemory();
184         startTime = System.currentTimeMillis();
185
186         try {
187             renderer.setupFontInfo(fontInfo);
188             renderer.startRenderer(outputStream);
189         } catch (FOPException fe) {
190             throw new SAXException JavaDoc(fe);
191         } catch (IOException JavaDoc e) {
192             throw new SAXException JavaDoc(e);
193         }
194     }
195
196     public void stopRenderer()
197     throws SAXException JavaDoc {
198         /*
199           Force the processing of any more queue elements,
200           even if they are not resolved.
201         */

202         try {
203             processQueue(true);
204             renderer.stopRenderer(outputStream);
205         } catch (FOPException e) {
206             throw new SAXException JavaDoc(e);
207         }
208         catch (IOException JavaDoc e) {
209             throw new SAXException JavaDoc(e);
210         }
211
212         if (MEM_PROFILE_WITH_GC)
213             System.gc(); // This takes time but gives better results
214

215         long memoryNow = runtime.totalMemory() - runtime.freeMemory();
216         long memoryUsed = (memoryNow - initialMemory) / 1024L;
217
218         log.debug("Initial heap size: " + (initialMemory/1024L) + "Kb");
219         log.debug("Current heap size: " + (memoryNow/1024L) + "Kb");
220         log.debug("Total memory used: " + memoryUsed + "Kb");
221
222         if (!MEM_PROFILE_WITH_GC) {
223             log.debug(" Memory use is indicative; no GC was performed");
224             log.debug(" These figures should not be used comparatively");
225         }
226
227         long timeUsed = System.currentTimeMillis() - startTime;
228
229         log.debug("Total time used: " + timeUsed + "ms");
230         log.debug("Pages rendered: " + pageCount);
231         if (pageCount != 0) {
232             log.debug("Avg render time: " + (timeUsed / pageCount) + "ms/page");
233         }
234     }
235
236     /**
237       Format the PageSequence. The PageSequence
238       formats Pages and adds them to the AreaTree,
239       which subsequently calls the StreamRenderer
240       instance (this) again to render the page.
241       At this time the page might be printed
242       or it might be queued. A page might not
243       be renderable immediately if the IDReferences
244       are not all valid. In this case we defer
245       the rendering until they are all valid.
246     */

247     public void render(PageSequence pageSequence)
248     throws SAXException JavaDoc {
249         AreaTree a = new AreaTree(this);
250         a.setFontInfo(fontInfo);
251
252         for(int i = 0; i < extensions.size(); i++ ) {
253             ExtensionObj ext = (ExtensionObj)extensions.get(i);
254             try {
255                 ext.format(a);
256             } catch (FOPException fope) {
257                 throw new SAXException JavaDoc(fope);
258             }
259         }
260
261         try {
262             pageSequence.format(a);
263         } catch (FOPException e) {
264             throw new SAXException JavaDoc(e);
265         }
266         this.results.haveFormattedPageSequence(pageSequence);
267         log.debug("Last page-sequence produced "+pageSequence.getPageCount()+" pages.");
268     }
269
270     public synchronized void queuePage(Page page)
271     throws FOPException, IOException JavaDoc {
272
273         // process markers
274
PageSequence pageSequence = page.getPageSequence();
275         if (pageSequence != currentPageSequence) {
276             currentPageSequence = pageSequence;
277             currentPageSequenceMarkers = null;
278         }
279         ArrayList JavaDoc markers = page.getMarkers();
280         if (markers != null) {
281             if (documentMarkers == null) {
282                 documentMarkers = new ArrayList JavaDoc();
283             }
284             if (currentPageSequenceMarkers == null) {
285                 currentPageSequenceMarkers = new ArrayList JavaDoc();
286             }
287             for (int i=0;i<markers.size();i++) {
288                 Marker marker = (Marker)markers.get(i);
289                 marker.releaseRegistryArea();
290                 currentPageSequenceMarkers.add(marker);
291                 documentMarkers.add(marker);
292             }
293         }
294         
295         /*
296           Try to optimise on the common case that there are
297           no pages pending and that all ID references are
298           valid on the current pages. This short-cuts the
299           pipeline and renders the area immediately.
300         */

301         if ((renderQueue.size() == 0) && idReferences.isEveryIdValid()) {
302             renderer.render(page, outputStream);
303         } else {
304             RenderQueueEntry entry = new RenderQueueEntry(page);
305             renderQueue.add(entry);
306             /*
307               The just-added entry could (possibly) resolve the
308               waiting entries, so we try to process the queue
309               now to see.
310             */

311             processQueue(false);
312         }
313         pageCount++;
314     }
315
316     /**
317       Try to process the queue from the first entry forward.
318       If an entry can't be processed, then the queue can't
319       move forward, so return.
320     */

321     private synchronized void processQueue(boolean force)
322     throws FOPException, IOException JavaDoc {
323         while (renderQueue.size() > 0) {
324             RenderQueueEntry entry = (RenderQueueEntry) renderQueue.get(0);
325             if ((!force) && (!entry.isResolved()))
326                 break;
327
328             renderer.render(entry.getPage(), outputStream);
329             renderQueue.remove(0);
330         }
331     }
332
333     /**
334       A RenderQueueEntry consists of the Page to be queued,
335       plus a list of outstanding ID references that need to be
336       resolved before the Page can be renderered.<P>
337     */

338     class RenderQueueEntry {
339         /*
340           The Page that has outstanding ID references.
341         */

342         private Page page;
343
344         /*
345           A list of ID references (names).
346         */

347         private ArrayList JavaDoc unresolvedIdReferences = new ArrayList JavaDoc();
348
349         public RenderQueueEntry(Page page) {
350             this.page = page;
351
352             Iterator JavaDoc e = idReferences.getInvalidElements();
353             while (e.hasNext())
354                 unresolvedIdReferences.add(e.next());
355         }
356
357         public Page getPage() {
358             return page;
359         }
360
361         /**
362           See if the outstanding references are resolved
363           in the current copy of IDReferences.
364         */

365         public boolean isResolved() {
366             if ((unresolvedIdReferences.size() == 0) || idReferences.isEveryIdValid())
367                 return true;
368
369             //
370
// See if any of the unresolved references are still unresolved.
371
//
372
for (int i = 0; i< unresolvedIdReferences.size(); i++)
373                 if (!idReferences.doesIDExist((String JavaDoc)unresolvedIdReferences.get(i)))
374                     return false;
375
376             unresolvedIdReferences.clear();
377             return true;
378         }
379     }
380
381     // Auxillary function for retrieving markers.
382
public ArrayList JavaDoc getDocumentMarkers() {
383         return documentMarkers;
384     }
385
386     // Auxillary function for retrieving markers.
387
public PageSequence getCurrentPageSequence() {
388         return currentPageSequence;
389     }
390
391     // Auxillary function for retrieving markers.
392
public ArrayList JavaDoc getCurrentPageSequenceMarkers() {
393         return currentPageSequenceMarkers;
394     }
395 }
396
Popular Tags