001: /* ========================================================================
002: * JCommon : a free general purpose class library for the Java(tm) platform
003: * ========================================================================
004: *
005: * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
006: *
007: * Project Info: http://www.jfree.org/jcommon/index.html
008: *
009: * This library is free software; you can redistribute it and/or modify it
010: * under the terms of the GNU Lesser General Public License as published by
011: * the Free Software Foundation; either version 2.1 of the License, or
012: * (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but
015: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017: * License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022: * USA.
023: *
024: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025: * in the United States and other countries.]
026: *
027: * --------------------
028: * ReportGenerator.java
029: * --------------------
030: * (C)opyright 2002-2005, by Thomas Morgner and Contributors.
031: *
032: * Original Author: Thomas Morgner (taquera@sherito.org);
033: * Contributor(s): David Gilbert (for Object Refinery Limited);
034: *
035: * $Id: ParserFrontend.java,v 1.8 2005/11/14 10:58:19 mungady Exp $
036: *
037: * Changes
038: * -------
039: * 10-May-2002 : Initial version
040: * 12-Dec-2002 : Fixed issues reported by Checkstyle (DG);
041: * 29-Apr-2003 : Distilled from the JFreeReport project and moved into JCommon
042: *
043: */
044:
045: package org.jfree.xml;
046:
047: import java.io.BufferedInputStream;
048: import java.io.IOException;
049: import java.net.URL;
050: import javax.xml.parsers.ParserConfigurationException;
051: import javax.xml.parsers.SAXParser;
052: import javax.xml.parsers.SAXParserFactory;
053:
054: import org.jfree.util.Log;
055: import org.xml.sax.EntityResolver;
056: import org.xml.sax.InputSource;
057: import org.xml.sax.SAXException;
058: import org.xml.sax.XMLReader;
059:
060: /**
061: * The reportgenerator initializes the parser and provides an interface
062: * the the default parser.
063: *
064: * To create a report from an URL, use
065: * <code>
066: * ReportGenerator.getInstance().parseReport (URL myURl, URL contentBase);
067: * </code>
068: *
069: * @author Thomas Morgner
070: */
071: public class ParserFrontend {
072:
073: /** The report handler. */
074: private FrontendDefaultHandler defaulthandler;
075:
076: /** The parser factory. */
077: private SAXParserFactory factory;
078:
079: /** The DTD. */
080: private EntityResolver entityResolver;
081:
082: /** A flag indicating whether to use a DTD to validate the xml input. */
083: private boolean validateDTD;
084:
085: /**
086: * Creates a new report generator. The generator uses the singleton pattern by default,
087: * so use generator.getInstance() to get the generator.
088: *
089: * @param parser the parser that is used to coordinate the parsing process.
090: */
091: protected ParserFrontend(final FrontendDefaultHandler parser) {
092: if (parser == null) {
093: throw new NullPointerException();
094: }
095: this .defaulthandler = parser;
096: }
097:
098: /**
099: * Returns <code>true</code> if the report definition should be validated against the
100: * DTD, and <code>false</code> otherwise.
101: *
102: * @return A boolean.
103: */
104: public boolean isValidateDTD() {
105: return this .validateDTD;
106: }
107:
108: /**
109: * Sets a flag that controls whether or not the report definition is validated
110: * against the DTD.
111: *
112: * @param validateDTD the flag.
113: */
114: public void setValidateDTD(final boolean validateDTD) {
115: this .validateDTD = validateDTD;
116: }
117:
118: /**
119: * Returns the entity resolver.
120: *
121: * @return The entity resolver.
122: */
123: public EntityResolver getEntityResolver() {
124: return this .entityResolver;
125: }
126:
127: /**
128: * Sets the entity resolver.
129: *
130: * @param entityResolver the entity resolver.
131: */
132: public void setEntityResolver(final EntityResolver entityResolver) {
133: this .entityResolver = entityResolver;
134: }
135:
136: /**
137: * Returns a SAX parser.
138: *
139: * @return a SAXParser.
140: *
141: * @throws ParserConfigurationException if there is a problem configuring the parser.
142: * @throws SAXException if there is a problem with the parser initialisation
143: */
144: protected SAXParser getParser()
145: throws ParserConfigurationException, SAXException {
146: if (this .factory == null) {
147: this .factory = SAXParserFactory.newInstance();
148: if (isValidateDTD()) {
149: try {
150: // dont touch the validating feature, if not needed ..
151: this .factory.setValidating(true);
152: } catch (Exception ex) {
153: // the parser does not like the idea of validating ...
154: Log
155: .debug(
156: "The parser will not validate the xml document.",
157: ex);
158: }
159: }
160: }
161: return this .factory.newSAXParser();
162: }
163:
164: /**
165: * Sets the default handler used for parsing reports. This handler is used to
166: * initiate parsing.
167: *
168: * @param handler the handler.
169: */
170: public void setDefaultHandler(final FrontendDefaultHandler handler) {
171: if (handler == null) {
172: throw new NullPointerException();
173: }
174: this .defaulthandler = handler;
175: }
176:
177: /**
178: * Returns the ElementDefinitionHandler used for parsing reports.
179: *
180: * @return the report handler.
181: */
182: public FrontendDefaultHandler getDefaultHandler() {
183: return this .defaulthandler;
184: }
185:
186: /**
187: * Creates a new instance of the currently set default handler and sets the contentbase
188: * for the handler to <code>contentBase</code>.
189: *
190: * @param contentBase the content base.
191: *
192: * @return the report handler.
193: */
194: protected FrontendDefaultHandler createDefaultHandler(
195: final URL contentBase) {
196: final FrontendDefaultHandler handler = getDefaultHandler()
197: .newInstance();
198: if (contentBase != null) {
199: handler.setConfigProperty(Parser.CONTENTBASE_KEY,
200: contentBase.toExternalForm());
201: }
202: return handler;
203: }
204:
205: /**
206: * Parses an XML report template file.
207: *
208: * @param input the input source.
209: * @param contentBase the content base.
210: *
211: * @return the report.
212: *
213: * @throws ElementDefinitionException if an error occurred.
214: */
215: protected Object parse(final InputSource input,
216: final URL contentBase) throws ElementDefinitionException {
217: try {
218: final SAXParser parser = getParser();
219: final XMLReader reader = parser.getXMLReader();
220:
221: try {
222: reader.setFeature(
223: "http://xml.org/sax/features/validation",
224: isValidateDTD());
225: } catch (SAXException se) {
226: Log
227: .debug(
228: "The XMLReader will not validate the xml document.",
229: se);
230: }
231: final FrontendDefaultHandler handler = createDefaultHandler(contentBase);
232: configureReader(reader, handler);
233: try {
234: reader.setContentHandler(handler);
235: reader.setDTDHandler(handler);
236: if (getEntityResolver() != null) {
237: reader.setEntityResolver(getEntityResolver());
238: }
239: reader.setErrorHandler(handler);
240: reader.parse(input);
241: return handler.getResult();
242: } catch (IOException e) {
243: throw new ElementDefinitionException(e);
244: }
245: } catch (ParserConfigurationException e) {
246: throw new ElementDefinitionException(e);
247: } catch (SAXException e) {
248: throw new ElementDefinitionException(e);
249: }
250: }
251:
252: /**
253: * Configures the xml reader. Use this to set features or properties
254: * before the documents get parsed.
255: *
256: * @param handler the parser implementation that will handle the SAX-Callbacks.
257: * @param reader the xml reader that should be configured.
258: */
259: protected void configureReader(final XMLReader reader,
260: final FrontendDefaultHandler handler) {
261: try {
262: reader.setProperty(
263: "http://xml.org/sax/properties/lexical-handler",
264: handler.getCommentHandler());
265: } catch (SAXException se) {
266: Log
267: .debug("Comments are not supported by this SAX implementation.");
268: }
269: }
270:
271: /**
272: * Parses an XML file which is loaded using the given URL. All
273: * needed relative file- and resourcespecification are loaded
274: * using the URL <code>contentBase</code> as base.
275: * <p>
276: * After the report is generated, the ReportDefinition-source and the contentbase are
277: * stored as string in the reportproperties.
278: *
279: * @param file the URL for the report template file.
280: * @param contentBase the URL for the report template content base.
281: *
282: * @return the parsed report.
283: *
284: * @throws IOException if an I/O error occurs.
285: * @throws ElementDefinitionException if there is a problem parsing the report template.
286: */
287: public Object parse(final URL file, final URL contentBase)
288: throws ElementDefinitionException, IOException {
289: if (file == null) {
290: throw new NullPointerException("File may not be null");
291: }
292:
293: final BufferedInputStream bin = new BufferedInputStream(file
294: .openStream());
295: final InputSource in = new InputSource(bin);
296: in.setSystemId(file.toString());
297: final Object result = parse(in, contentBase);
298: bin.close();
299: return result;
300: }
301:
302: }
|