producer abort + timezone support
[mir.git] / source / mir / util / XMLReader.java
1 /*
2  * Copyright (C) 2001, 2002 The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
6  * Mir is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Mir is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Mir; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with  any library licensed under the Apache Software License,
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23  * (or with modified versions of the above that use the same license as the above),
24  * and distribute linked combinations including the two.  You must obey the
25  * GNU General Public License in all respects for all of the code used other than
26  * the above mentioned libraries.  If you modify this file, you may extend this
27  * exception to your version of the file, but you are not obligated to do so.
28  * If you do not wish to do so, delete this exception statement from your version.
29  */
30 package mir.util;
31
32 import java.io.FileInputStream;
33 import java.io.InputStream;
34 import java.util.HashMap;
35 import java.util.Map;
36 import java.util.Stack;
37
38 import javax.xml.parsers.ParserConfigurationException;
39 import javax.xml.parsers.SAXParser;
40 import javax.xml.parsers.SAXParserFactory;
41
42 import multex.Exc;
43 import multex.Failure;
44
45 import org.xml.sax.Attributes;
46 import org.xml.sax.InputSource;
47 import org.xml.sax.Locator;
48 import org.xml.sax.SAXException;
49 import org.xml.sax.SAXParseException;
50 import org.xml.sax.helpers.DefaultHandler;
51
52 public class XMLReader {
53   private Locator locator;
54   private String filename;
55   private boolean namespaceAware;
56
57   public XMLReader() {
58     this(false);
59   }
60
61   public XMLReader(boolean aNameSpaceAware) {
62     namespaceAware = aNameSpaceAware;
63     filename="";
64   }
65
66   public void parseFile(String aFileName, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
67     filename= aFileName;
68     try {
69       parseInputStream(new FileInputStream(aFileName), aRootHandler);
70     }
71     catch (Throwable t) {
72       throw new XMLReaderFailure(t);
73     }
74   }
75
76   public void parseInputStream(InputStream anInputStream, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
77     try {
78       SAXParserFactory parserFactory = SAXParserFactory.newInstance();
79
80       parserFactory.setNamespaceAware(true);
81       parserFactory.setValidating(true);
82
83       XMLReaderHandler handler = new XMLReaderHandler(parserFactory, aRootHandler);
84
85       handler.processInputStream(anInputStream);
86     }
87     catch (Throwable e) {
88       Throwable t = ExceptionFunctions.traceCauseException(e);
89
90       if (t instanceof XMLReaderExc) {
91         if (locator!=null && filename!=null)
92           ((XMLReaderExc) t).setLocation(filename, locator.getLineNumber(), locator.getColumnNumber());
93         throw (XMLReaderExc) t;
94       }
95
96       if (t instanceof XMLReaderFailure) {
97         throw (XMLReaderFailure) t;
98       }
99
100       throw new XMLReaderFailure(t);
101     }
102   }
103
104   private class XMLReaderHandler extends DefaultHandler {
105     private SAXParserFactory parserFactory;
106     private SectionsManager manager;
107     private InputSource inputSource;
108
109     public XMLReaderHandler(SAXParserFactory aParserFactory, SectionHandler aRootHandler) {
110       super();
111
112       parserFactory=aParserFactory;
113       manager = new SectionsManager();
114       manager.pushHandler(aRootHandler);
115    }
116
117     public void setDocumentLocator(Locator aLocator) {
118       locator=aLocator;
119     }
120
121     private void processInputStream(InputStream anInputStream) throws XMLReaderExc, XMLReaderFailure {
122       try {
123         SAXParser parser=parserFactory.newSAXParser();
124
125         inputSource = new InputSource(anInputStream);
126         parser.parse(inputSource, this);
127       }
128       catch (ParserConfigurationException e) {
129         throw new XMLReaderExc("Internal exception: "+e.getMessage());
130       }
131       catch (Throwable e) {
132         throw new XMLReaderFailure(e);
133       }
134     }
135
136     public void startElement(String aUri, String aLocalName, String aQualifiedName, Attributes anAttributes) throws SAXException {
137       Map attributesMap;
138       int i;
139
140       try {
141         attributesMap = new HashMap();
142
143         if (namespaceAware)
144           for (i=0; i<anAttributes.getLength(); i++)
145             attributesMap.put(new XMLName(anAttributes.getURI(i), anAttributes.getLocalName(i)), anAttributes.getValue(i));
146         else
147           for (i=0; i<anAttributes.getLength(); i++)
148             attributesMap.put(anAttributes.getLocalName(i), anAttributes.getValue(i));
149
150         SectionHandler handler = manager.currentHandler().startElement(new XMLName(aUri, aLocalName), attributesMap);
151
152         manager.pushHandler( handler );
153       }
154       catch (XMLReaderExc e) {
155         throw new SAXParseException(e.getMessage(), null, e);
156       }
157       catch (Exception e) {
158         throw new SAXException(e);
159       }
160     }
161
162     public void endElement(String aUri, String aLocalName, String aQualifiedName) throws SAXException {
163       try
164       {
165         if (!aQualifiedName.equals("include")) {
166           SectionHandler handler = manager.popHandler();
167
168           handler.finishSection();
169
170           if (!manager.isEmpty()) {
171             manager.currentHandler().endElement(handler);
172           }
173         }
174       }
175       catch (XMLReaderExc e) {
176         throw new SAXParseException(e.getMessage(), null, e);
177       }
178       catch (Exception e) {
179         throw new SAXException(e);
180       }
181     }
182
183     public void characters(char[] aBuffer, int aStart, int anEnd) throws SAXException {
184       try {
185         String text = new String(aBuffer, aStart, anEnd);
186
187         manager.currentHandler().characters(text);
188       }
189       catch (XMLReaderExc e) {
190         throw new SAXParseException(e.getMessage(), null, e);
191       }
192       catch (Exception e) {
193         throw new SAXException(e);
194       }
195     }
196   }
197
198   private class SectionsManager {
199     Stack handlerStack;
200
201     public SectionsManager() {
202       handlerStack = new Stack();
203     }
204
205     public void pushHandler(SectionHandler aSectionHandler) {
206       handlerStack.push(aSectionHandler);
207     }
208
209     public SectionHandler popHandler() {
210       return (SectionHandler) handlerStack.pop();
211     }
212
213     public SectionHandler currentHandler() {
214       return (SectionHandler) handlerStack.peek();
215     }
216
217     public boolean isEmpty() {
218       return handlerStack.isEmpty();
219     }
220   }
221
222   public static interface SectionHandler {
223     public abstract SectionHandler startElement(XMLName aTag, Map anAttributes) throws XMLReaderExc;
224
225     public abstract void endElement(SectionHandler aHandler) throws XMLReaderExc;
226
227     public void characters(String aCharacters) throws XMLReaderExc;
228
229     public void finishSection() throws XMLReaderExc;
230   }
231
232   public static abstract class AbstractSectionHandler implements SectionHandler {
233     public SectionHandler startElement(XMLName aTag, Map anAttributes) throws XMLReaderExc {
234       return startElement(aTag.getLocalName(), anAttributes);
235     };
236
237     public SectionHandler startElement(String aLocalName, Map anAttributes) throws XMLReaderExc {
238       return null;
239     };
240
241     public void endElement(SectionHandler aHandler) throws XMLReaderExc {
242     };
243
244     public void finishSection() throws XMLReaderExc {
245     }
246
247     public void characters(String aCharacters) throws XMLReaderExc {
248       if ( aCharacters.trim().length() > 0) {
249         throw new XMLReaderExc("Text not allowed");
250       }
251     }
252   }
253
254   public static class XMLReaderExc extends Exc {
255     private boolean hasLocation;
256     private String filename;
257     private int lineNr;
258     private int columnNr;
259
260     public XMLReaderExc(String aMessage) {
261       super(aMessage);
262       hasLocation = false;
263     }
264
265     protected void setLocation(String aFilename, int aLineNr, int aColumnNr) {
266       filename = aFilename;
267       lineNr = aLineNr;
268       columnNr = aColumnNr;
269       hasLocation = true;
270     }
271
272     public boolean getHasLocation() {
273       return hasLocation;
274     }
275
276     public int getLineNr() {
277       return lineNr;
278     }
279
280     public int getColumnNr() {
281       return columnNr;
282     }
283
284     public String getFilename() {
285       return filename;
286     }
287   }
288
289   public static class XMLReaderFailure extends Failure {
290     public XMLReaderFailure(String aMessage, Throwable aCause) {
291       super(aMessage, aCause);
292     }
293
294     public XMLReaderFailure(Throwable aCause) {
295       super(aCause.getMessage(), aCause);
296     }
297   }
298
299   public static class XMLName {
300     private String namespaceURI;
301     private String localName;
302
303     public XMLName(String aLocalName) {
304       this(aLocalName, null);
305     }
306
307     public XMLName(String aNamespaceURI, String aLocalName) {
308       namespaceURI = aNamespaceURI;
309       localName = aLocalName;
310     }
311
312     public String getNamespaceURI() {
313       return namespaceURI;
314     }
315
316     public String getLocalName() {
317       return localName;
318     }
319
320     public int hashCode() {
321       if (namespaceURI == null)
322         return localName.hashCode();
323       else
324         return localName.hashCode() + 3*namespaceURI.hashCode();
325     }
326
327     public String toString() {
328       return namespaceURI+":"+localName;
329     }
330
331     public boolean equals(Object anObject) {
332       if (anObject instanceof XMLName) {
333         if (namespaceURI==null)
334           return (((XMLName) anObject).namespaceURI == null) &&
335                  localName.equals(((XMLName) anObject).localName);
336         else
337           return namespaceURI.equals(((XMLName) anObject).namespaceURI) &&
338                  localName.equals(((XMLName) anObject).localName);
339       }
340       else
341         return false;
342     }
343   }
344
345 }