KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > fo > FOTreeBuilder


1 /*
2  * $Id: FOTreeBuilder.java,v 1.30.2.9 2003/05/14 15:28:38 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.fo;
52
53 // FOP
54
import org.apache.fop.apps.FOPException;
55 import org.apache.fop.apps.StreamRenderer;
56 import org.apache.fop.fo.pagination.PageSequence;
57 import org.apache.fop.extensions.ExtensionObj;
58
59 // Avalon
60
import org.apache.avalon.framework.logger.Logger;
61
62 // SAX
63
import org.xml.sax.helpers.DefaultHandler JavaDoc;
64 import org.xml.sax.SAXException JavaDoc;
65 import org.xml.sax.Attributes JavaDoc;
66 import org.xml.sax.Locator JavaDoc;
67
68 // Java
69
import java.util.HashMap JavaDoc;
70 import java.util.ArrayList JavaDoc;
71
72 /**
73  * SAX Handler that builds the formatting object tree.
74  *
75  * Modified by Mark Lillywhite mark-fop@inomial.com. Now uses
76  * StreamRenderer to automagically render the document as
77  * soon as it receives a page-sequence end-tag. Also,
78  * calls methods to set up and shut down the renderer at
79  * the beginning and end of the FO document. Finally,
80  * supresses adding the PageSequence object to the Root,
81  * since it is parsed immediately.
82  */

83 public class FOTreeBuilder extends DefaultHandler JavaDoc implements TreeBuilder {
84
85     /**
86      * table mapping element names to the makers of objects
87      * representing formatting objects
88      */

89     protected HashMap JavaDoc fobjTable = new HashMap JavaDoc();
90
91     protected ArrayList JavaDoc namespaces = new ArrayList JavaDoc();
92
93     /**
94      * class that builds a property list for each formatting object
95      */

96     protected HashMap JavaDoc propertylistTable = new HashMap JavaDoc();
97
98     /**
99      * current formatting object being handled
100      */

101     protected FObj currentFObj = null;
102
103     /**
104      * the root of the formatting object tree
105      */

106     protected FObj rootFObj = null;
107
108     /**
109      * set of names of formatting objects encountered but unknown
110      */

111     protected HashMap JavaDoc unknownFOs = new HashMap JavaDoc();
112
113     /**
114      *
115      * The class that handles formatting and rendering to a stream
116      * (mark-fop@inomial.com)
117      */

118     private StreamRenderer streamRenderer;
119
120     private Logger log;
121
122     private Locator JavaDoc locator;
123     
124     private int errorCount = 0;
125
126     public FOTreeBuilder() {}
127
128     public void setLogger(Logger logger) {
129         log = logger;
130     }
131
132     
133     
134     public void setStreamRenderer(StreamRenderer streamRenderer) {
135         this.streamRenderer = streamRenderer;
136     }
137
138     public StreamRenderer getStreamRenderer() {
139         return this.streamRenderer;
140     }
141
142     /**
143      * add a mapping from element name to maker.
144      *
145      * @param namespaceURI namespace URI of formatting object element
146      * @param maker Maker for class representing formatting object
147      */

148     public void addMapping(String JavaDoc namespaceURI, HashMap JavaDoc table) {
149         this.fobjTable.put(namespaceURI, table);
150         this.namespaces.add(namespaceURI.intern());
151     }
152
153     /**
154      * add a mapping from element name to maker.
155      *
156      * @param namespaceURI namespace URI of formatting object element
157      * @param maker Maker for class representing formatting object
158      */

159     public void addPropertyList(String JavaDoc namespaceURI, HashMap JavaDoc list) {
160         PropertyListBuilder plb;
161         plb = (PropertyListBuilder)this.propertylistTable.get(namespaceURI);
162         if (plb == null) {
163             plb = new PropertyListBuilder();
164             plb.addList(list);
165             this.propertylistTable.put(namespaceURI, plb);
166         } else {
167             plb.addList(list);
168         }
169     }
170
171     /**
172      * add a mapping from element name to maker.
173      *
174      * @param namespaceURI namespace URI of formatting object element
175      * @param localName local name of formatting object element
176      * @param maker Maker for class representing formatting object
177      */

178     public void addElementPropertyList(String JavaDoc namespaceURI, String JavaDoc localName,
179                                        HashMap JavaDoc list) {
180         PropertyListBuilder plb;
181         plb = (PropertyListBuilder)this.propertylistTable.get(namespaceURI);
182         if (plb == null) {
183             plb = new PropertyListBuilder();
184             plb.addElementList(localName, list);
185             this.propertylistTable.put(namespaceURI, plb);
186         } else {
187             plb.addElementList(localName, list);
188         }
189     }
190
191     public void addPropertyListBuilder(String JavaDoc namespaceURI,
192                                        PropertyListBuilder propbuilder) {
193         PropertyListBuilder plb;
194         plb = (PropertyListBuilder)this.propertylistTable.get(namespaceURI);
195         if (plb == null) {
196             this.propertylistTable.put(namespaceURI, propbuilder);
197         } else {
198             // Error already added
199
}
200     }
201
202     /**
203      * SAX Handler for characters
204      */

205     public void characters(char data[], int start, int length) {
206         if(currentFObj != null) {
207             currentFObj.addCharacters(data, start, length);
208         }
209     }
210
211     /**
212      * SAX Handler for the end of an element
213      */

214     public void endElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc rawName)
215     throws SAXException JavaDoc {
216         currentFObj.end();
217
218         //
219
// mark-fop@inomial.com - tell the stream renderer to render
220
// this page-sequence
221
//
222
if(currentFObj instanceof PageSequence) {
223             streamRenderer.render((PageSequence) currentFObj);
224         } else if(currentFObj instanceof ExtensionObj) {
225             if(!(currentFObj.getParent() instanceof ExtensionObj)) {
226                 streamRenderer.addExtension((ExtensionObj)currentFObj);
227             }
228         }
229
230         currentFObj = (FObj)currentFObj.getParent();
231     }
232
233     /**
234      * SAX Handler for the start of the document
235      */

236     public void startDocument()
237     throws SAXException JavaDoc {
238         rootFObj = null; // allows FOTreeBuilder to be reused
239
log.info("building formatting object tree");
240         streamRenderer.startRenderer();
241     }
242
243     public void endDocument()
244     throws SAXException JavaDoc {
245         log.info("Parsing of document complete, stopping renderer");
246         streamRenderer.stopRenderer();
247     }
248
249     public void setDocumentLocator(Locator JavaDoc locator) {
250         this.locator = locator;
251     }
252     
253     private String JavaDoc formatLocator(Locator JavaDoc locator) {
254         if (locator == null) {
255             return "";
256         } else {
257             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
258             if (locator.getSystemId() != null) {
259                 sb.append(locator.getSystemId());
260             } else if (locator.getPublicId() != null) {
261                 sb.append(locator.getPublicId());
262             } else {
263                 sb.append("Unknown source");
264             }
265             sb.append(" (line: ");
266             sb.append(locator.getLineNumber());
267             sb.append(", col: ");
268             sb.append(locator.getColumnNumber());
269             sb.append(")");
270             return sb.toString();
271         }
272     }
273     
274     /**
275      * SAX Handler for the start of an element
276      */

277     public void startElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc rawName,
278                              Attributes JavaDoc attlist) throws SAXException JavaDoc {
279         /* the formatting object started */
280         FObj fobj;
281
282         /* the maker for the formatting object started */
283         FObj.Maker fobjMaker = null;
284
285         /* look up Maker for the element */
286         HashMap JavaDoc table = (HashMap JavaDoc)fobjTable.get(uri);
287         if(table != null) {
288             fobjMaker = (FObj.Maker)table.get(localName);
289         }
290
291         PropertyListBuilder currentListBuilder =
292             (PropertyListBuilder)this.propertylistTable.get(uri);
293
294         boolean foreignXML = false;
295         String JavaDoc systemId=null;
296         int line = -1;
297         int column = -1;
298         if (locator!=null) {
299             systemId = locator.getSystemId();
300             line = locator.getLineNumber();
301             column = locator.getColumnNumber();
302         }
303         if (fobjMaker == null) {
304             String JavaDoc fullName = uri + "^" + localName;
305             if (!this.unknownFOs.containsKey(fullName)) {
306                 this.unknownFOs.put(fullName, "");
307                 StringBuffer JavaDoc sb = new StringBuffer JavaDoc(128);
308                 sb.append("Unsupported element encountered: ");
309                 sb.append(localName);
310                 sb.append(" (Namespace: ");
311                 sb.append("".equals(uri) ? "default" : uri);
312                 sb.append("). ");
313                 sb.append("Source context: ");
314                 if (locator != null) {
315                     sb.append(formatLocator(locator));
316                 } else {
317                     sb.append("unavailable");
318                 }
319                 log.error(sb.toString());
320                 if (this.errorCount == 0) {
321                     log.error("Expected XSL-FO (root, page-sequence, etc.), "
322                         + "SVG (svg, rect, etc.) or elements from another "
323                         + "supported language.");
324                 }
325                 this.errorCount++;
326             }
327             if(namespaces.contains(uri.intern())) {
328                 // fall back
329
fobjMaker = new Unknown.Maker();
330             } else {
331                 fobjMaker = new UnknownXMLObj.Maker(uri, localName);
332                 foreignXML = true;
333             }
334         }
335
336         try {
337             PropertyList list = null;
338             if (currentListBuilder != null) {
339                 list =
340                     currentListBuilder.makeList(uri, localName, attlist,
341                                                 (currentFObj == null) ? null
342                                                 : currentFObj.properties, currentFObj);
343             } else if(foreignXML) {
344                 list = new DirectPropertyListBuilder.AttrPropertyList(attlist);
345             } else {
346                 if(currentFObj == null) {
347                     throw new FOPException("Invalid XML or missing namespace",
348                                            systemId, line, column);
349                 }
350                 list = currentFObj.properties;
351             }
352             fobj = fobjMaker.make(currentFObj, list, systemId, line, column);
353             fobj.setLogger(log);
354         } catch (FOPException e) {
355             throw new SAXException JavaDoc(e);
356         }
357
358         if (rootFObj == null) {
359             rootFObj = fobj;
360             if (!fobj.getName().equals("fo:root")) {
361                 if (fobj.getName().equals("root")) {
362                     throw new SAXException JavaDoc(new FOPException(
363                         "Root element is missing the namespace declaration: "
364                         + "http://www.w3.org/1999/XSL/Format",
365                         systemId, line, column));
366                 } else {
367                     throw new SAXException JavaDoc(new FOPException(
368                         "Root element must be root, not "
369                         + fobj.getName(), systemId, line, column));
370                 }
371             }
372         } else if(!(fobj instanceof org.apache.fop.fo.pagination.PageSequence)) {
373             currentFObj.addChild(fobj);
374         }
375
376         currentFObj = fobj;
377     }
378
379     public void reset() {
380         currentFObj = null;
381         rootFObj = null;
382         streamRenderer = null;
383         this.errorCount = 0;
384     }
385
386     public boolean hasData() {
387         return (rootFObj != null);
388     }
389
390 }
391
Popular Tags