001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.mq.xml;
023:
024: import java.util.Vector;
025: import javax.xml.parsers.SAXParser;
026: import javax.xml.parsers.SAXParserFactory;
027:
028: import org.xml.sax.Attributes;
029: import org.xml.sax.InputSource;
030: import org.xml.sax.SAXException;
031: import org.xml.sax.XMLReader;
032: import org.xml.sax.helpers.DefaultHandler;
033:
034: /**
035: * XElementProducer parses and provides an XElementConsumer XElement data. <p>
036: *
037: * An XElementProducer is a SAX based XML parser. This class provides a hybrid
038: * of the Event Based and DOM based XML parsing models. This is done by telling
039: * the XElementProducer which elements signal the start of a record, and when
040: * to generat an XElement. As the "record" XML elements are encountered,
041: * XElements are produced. These XElements create an in memory DOM tree of the
042: * element and all sub elements. After the "record" element has be fully read
043: * in through the use of SAX events, the "record" element, now in the form of
044: * an XElement, is passed to an XElementConsumer for processing.
045: *
046: * @author Hiram Chirino (Cojonudo14@hotmail.com)
047: * @created August 16, 2001
048: * @version $Revision: 57198 $
049: */
050: public class XElementProducer {
051:
052: private XElementConsumer consumer;
053: private Vector targetRecords = new Vector();
054: private Handler handler = new Handler();
055: private Exception thrownError = null;
056:
057: /**
058: * The Constructor must be passed the consumer object.
059: *
060: * @param consumerObject the object that will process data produced from
061: * this object.
062: */
063: public XElementProducer(XElementConsumer consumerObject) {
064: consumer = consumerObject;
065: }
066:
067: /**
068: * Adds a name to the list of element names which when encountered, will
069: * produce an XElement record.
070: *
071: * @param name
072: */
073: public void addElementRecord(String name) {
074: targetRecords.addElement(name);
075: }
076:
077: /**
078: * Clears all the previously added element record names.
079: */
080: public void clearElementRecords() {
081: targetRecords.removeAllElements();
082: }
083:
084: /**
085: * Starts parsing a file. As "record" elements are encountered, record
086: * XElements are produced and given to the XElementConsumer to process.
087: *
088: * @param is Description of Parameter
089: * @throws Exception includes IO errors, parse errors, or Exceptions thrown
090: * from the RecordConsumer.
091: */
092: public void parse(java.io.InputStream is) throws Exception {
093: if (consumer == null) {
094: throw new NullPointerException();
095: }
096: try {
097:
098: SAXParserFactory factory = SAXParserFactory.newInstance();
099: SAXParser parser = factory.newSAXParser();
100:
101: if (consumer instanceof org.xml.sax.ErrorHandler) {
102: XMLReader reader = parser.getXMLReader();
103: reader
104: .setErrorHandler((org.xml.sax.ErrorHandler) consumer);
105: }
106: thrownError = null;
107: parser.parse(new InputSource(is), handler);
108: } catch (SAXException e) {
109: if (thrownError != null) {
110: throw thrownError;
111: } else {
112: throw e;
113: }
114: }
115: }
116:
117: /**
118: * Starts parsing a file. As "record" elements are encountered, record
119: * XElements are produced and given to the XElementConsumer to process.
120: *
121: * @param url Description of Parameter
122: * @throws Exception includes IO errors, parse errors, or Exceptions thrown
123: * from the RecordConsumer.
124: */
125: public void parse(java.net.URL url) throws Exception {
126: if (consumer == null) {
127: throw new NullPointerException();
128: }
129: try {
130: SAXParserFactory factory = SAXParserFactory.newInstance();
131: SAXParser parser = factory.newSAXParser();
132:
133: if (consumer instanceof org.xml.sax.ErrorHandler) {
134: XMLReader reader = parser.getXMLReader();
135: reader
136: .setErrorHandler((org.xml.sax.ErrorHandler) consumer);
137: }
138: thrownError = null;
139: parser.parse(url.toExternalForm(), handler);
140: } catch (SAXException e) {
141: if (thrownError != null) {
142: throw thrownError;
143: } else {
144: throw e;
145: }
146: }
147: }
148:
149: //
150: // INNER CLASS : Handler
151: // Used to handle for SAX events.
152: //
153: // If we get an element whose name is in targetRecords vector then
154: // we start a new root XElement and set currentXElement to this object.
155: // currentXElement is always the top element that is being processed.
156: // (He's working like the top pointer of a stack)
157: //
158: // As sub elements are encountered, they will be added to the currentXElement
159: // and then they become the currentXElement.
160: //
161: // When the end of an element is encountered, then currentXElement
162: // is set to the parent of currentXElement.
163: //
164: // Exception processing is a little trick, read on:
165: // An XElementConsumer is allowed to throw any kind of exception
166: // when processing records. But since the SAX event based parser only allows
167: // you to throw SAXExceptions from it's event handler methods, this class
168: // uses the thrownError variable to store the thrown event. A SAXException
169: // is then generated to stop the SAXParser and the XElementProducer.parse()
170: // method checks to see if the thrownError variable was set, if so, then
171: // it throws the exception stored in thrownError.
172: //
173: /**
174: * @created August 16, 2001
175: */
176: class Handler extends DefaultHandler {
177: private XElement currentXElement;
178:
179: public void startDocument() throws SAXException {
180: try {
181: consumer.documentStartEvent();
182: } catch (Exception e) {
183: thrownError = e;
184: throw new SAXException(e.toString());
185: }
186: }
187:
188: public void endDocument() throws SAXException {
189: try {
190: consumer.documentEndEvent();
191: } catch (Exception e) {
192: thrownError = e;
193: throw new SAXException(e.toString());
194: }
195: }
196:
197: public void startElement(String uri, String localName,
198: String qname, Attributes atts) throws SAXException {
199: if (currentXElement != null) {
200: XElement o = new XElement(qname, atts);
201: currentXElement.addElement(o);
202: currentXElement = o;
203: } else {
204: if (targetRecords.size() == 0) {
205: currentXElement = new XElement(qname, atts);
206: } else {
207: for (int i = 0; i < targetRecords.size(); i++) {
208: if (qname.equals(targetRecords.elementAt(i))) {
209: currentXElement = new XElement(qname, atts);
210: break;
211: }
212: }
213: }
214: }
215: }
216:
217: public void endElement(String uri, String localName,
218: String qName) throws SAXException {
219: if (currentXElement != null) {
220: // Sanity Check :
221: if (!qName.equals(currentXElement.getName())) {
222: throw new SAXException(
223: "XElement parsing sanitity check failed");
224: }
225: XElement t = currentXElement;
226: currentXElement = currentXElement.getParent();
227: if (currentXElement == null) {
228: try {
229: consumer.recordReadEvent(t);
230: } catch (Exception e) {
231: thrownError = e;
232: throw new SAXException(e.toString());
233: }
234: }
235: }
236: }
237:
238: public void characters(char[] chars, int start, int length) {
239: if (length == 0) {
240: return;
241: }
242: if (currentXElement != null) {
243: currentXElement.add(new String(chars, start, length));
244: }
245: }
246: }
247:
248: }
|