2 * Copyright (C) 2001, 2002 The Mir-coders group
4 * This file is part of Mir.
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.
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.
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
20 * In addition, as a special exception, The Mir-coders gives permission to link
21 * the code of this program with the com.oreilly.servlet library, any library
22 * licensed under the Apache Software License, The Sun (tm) Java Advanced
23 * Imaging library (JAI), The Sun JIMI library (or with modified versions of
24 * the above that use the same license as the above), and distribute linked
25 * combinations including the two. You must obey the GNU General Public
26 * License in all respects for all of the code used other than the above
27 * mentioned libraries. If you modify this file, you may extend this exception
28 * to your version of the file, but you are not obligated to do so. If you do
29 * not wish to do so, delete this exception statement from your version.
33 import mir.config.exceptions.ConfigDefineNotKnownException;
34 import mir.config.exceptions.ConfigFailure;
36 import org.xml.sax.Attributes;
37 import org.xml.sax.InputSource;
38 import org.xml.sax.Locator;
39 import org.xml.sax.SAXException;
40 import org.xml.sax.SAXParseException;
42 import org.xml.sax.helpers.DefaultHandler;
45 import java.io.FileInputStream;
46 import java.io.FileNotFoundException;
47 import java.io.IOException;
49 import java.util.HashMap;
51 import java.util.Stack;
53 import javax.xml.parsers.ParserConfigurationException;
54 import javax.xml.parsers.SAXParser;
55 import javax.xml.parsers.SAXParserFactory;
58 public class ConfigReader {
59 final static String propertyTagName = "property";
60 final static String propertyNameAttribute = "name";
61 final static String propertyValueAttribute = "value";
62 final static String defineTagName = "define";
63 final static String defineNameAttribute = "name";
64 final static String defineValueAttribute = "value";
65 final static String includeTagName = "include";
66 final static String includeFileAttribute = "file";
68 public ConfigReader() {
72 public void parseFile(String aFileName, ConfigNodeBuilder aRootNode)
73 throws ConfigFailure {
75 SAXParserFactory parserFactory = SAXParserFactory.newInstance();
77 parserFactory.setNamespaceAware(false);
78 parserFactory.setValidating(true);
80 ConfigReaderHandler handler =
81 new ConfigReaderHandler(aRootNode, parserFactory);
83 handler.includeFile(aFileName);
84 } catch (Throwable e) {
85 if (e instanceof SAXParseException &&
86 ((SAXParseException) e).getException() instanceof ConfigFailure) {
87 throw (ConfigFailure) ((SAXParseException) e).getException();
90 throw new ConfigFailure(e.getMessage());
95 private class ConfigReaderHandler extends DefaultHandler {
96 ConfigNodeBuilder builder;
99 DefinesManager definesManager;
101 Stack includeFileStack;
102 SAXParserFactory parserFactory;
104 public ConfigReaderHandler(ConfigNodeBuilder aBuilder,
105 SAXParserFactory aParserFactory) {
109 nodeStack = new Stack();
110 includeFileStack = new Stack();
111 definesManager = new DefinesManager();
112 parserFactory = aParserFactory;
116 public String getLocatorDescription(Locator aLocator) {
117 return aLocator.getPublicId() + " (" + aLocator.getLineNumber() + ")";
120 public void setDocumentLocator(Locator aLocator) {
124 private void includeFile(String aFileName)
125 throws ConfigFailure, SAXParseException, SAXException {
128 InputSource inputSource;
129 System.err.println("about to include " + aFileName);
132 if (!includeFileStack.empty()) {
134 new File(new File((String) includeFileStack.peek()).getParent(),
137 file = new File(aFileName);
140 System.err.println("about to include " + file.getCanonicalPath());
142 if (includeFileStack.contains(file.getCanonicalPath())) {
143 throw new ConfigFailure("recursive inclusion of file " +
144 file.getCanonicalPath(), getLocatorDescription(locator));
147 parser = parserFactory.newSAXParser();
149 inputSource = new InputSource(new FileInputStream(file));
150 inputSource.setPublicId(file.getCanonicalPath());
152 includeFileStack.push(file.getCanonicalPath());
155 parser.parse(inputSource, this);
157 includeFileStack.pop();
159 } catch (ParserConfigurationException e) {
160 throw new ConfigFailure("Internal exception while including \"" +
161 aFileName + "\": " + e.getMessage(), e, getLocatorDescription(locator));
162 } catch (SAXParseException e) {
164 } catch (ConfigFailure e) {
166 } catch (FileNotFoundException e) {
167 throw new ConfigFailure("Include file \"" + aFileName +
168 "\" not found: " + e.getMessage(), e, getLocatorDescription(locator));
169 } catch (IOException e) {
170 throw new ConfigFailure("unable to open include file \"" + aFileName +
171 "\": " + e.getMessage(), e, getLocatorDescription(locator));
175 public void startElement(String aUri, String aTag, String aQualifiedName,
176 Attributes anAttributes) throws SAXException {
177 nodeStack.push(builder);
181 if (builder == null) {
182 throw new ConfigFailure("define, include and property tags cannot have content",
183 getLocatorDescription(locator));
186 if (aQualifiedName.equals(propertyTagName)) {
187 String name = anAttributes.getValue(propertyNameAttribute);
188 String value = anAttributes.getValue(propertyValueAttribute);
191 throw new ConfigFailure("property has no name attribute",
192 getLocatorDescription(locator));
193 } else if (value == null) {
194 throw new ConfigFailure("property \"" + name +
195 "\" has no value attribute", getLocatorDescription(locator));
198 builder.addProperty(name,
199 definesManager.resolve(value, getLocatorDescription(locator)),
200 value, getLocatorDescription(locator));
202 } else if (aQualifiedName.equals(defineTagName)) {
203 String name = anAttributes.getValue(defineNameAttribute);
204 String value = anAttributes.getValue(defineValueAttribute);
207 throw new ConfigFailure("define has no name attribute",
208 getLocatorDescription(locator));
209 } else if (value == null) {
210 throw new ConfigFailure("define \"" + name +
211 "\" has no value attribute", getLocatorDescription(locator));
214 definesManager.addDefine(name,
215 definesManager.resolve(value, getLocatorDescription(locator)));
217 } else if (aQualifiedName.equals(includeTagName)) {
218 String fileName = anAttributes.getValue(includeFileAttribute);
220 if (fileName == null) {
221 throw new ConfigFailure("include has no file attribute",
222 getLocatorDescription(locator));
225 includeFile(definesManager.resolve(fileName,
226 getLocatorDescription(locator)));
230 builder.makeSubNode(aQualifiedName, getLocatorDescription(locator));
232 } catch (ConfigFailure e) {
233 throw new SAXParseException(e.getMessage(), locator, e);
237 public void endElement(String aUri, String aTag, String aQualifiedName)
238 throws SAXParseException {
239 builder = (ConfigNodeBuilder) nodeStack.pop();
243 public void characters(char[] aBuffer, int aStart, int anEnd)
244 throws SAXParseException {
245 String text = new String(aBuffer, aStart, anEnd).trim();
247 if (text.length() > 0) {
248 throw new SAXParseException("Text not allowed", locator,
249 new ConfigFailure("text not allowed", getLocatorDescription(locator)));
254 private class DefinesManager {
257 public DefinesManager() {
258 defines = new HashMap();
261 public void addDefine(String aName, String anExpression) {
262 defines.put(aName, anExpression);
265 public String resolve(String anExpression, String aLocation)
266 throws ConfigFailure {
267 int previousPosition = 0;
269 int endOfNamePosition;
272 StringBuffer result = new StringBuffer();
274 while ((position = anExpression.indexOf("$", previousPosition)) >= 0) {
275 result.append(anExpression.substring(previousPosition, position));
277 if (position >= (anExpression.length() - 1)) {
278 result.append(anExpression.substring(position, anExpression.length()));
279 previousPosition = anExpression.length();
281 if (anExpression.charAt(position + 1) == '{') {
282 endOfNamePosition = anExpression.indexOf('}', position);
284 if (endOfNamePosition >= 0) {
285 name = anExpression.substring(position + 2, endOfNamePosition);
287 if (defines.containsKey(name)) {
288 result.append((String) defines.get(name));
289 previousPosition = endOfNamePosition + 1;
291 throw new ConfigDefineNotKnownException("Variable \"" + name +
292 "\" not defined", aLocation);
295 throw new ConfigFailure("Missing }", aLocation);
298 previousPosition = position + 2;
299 result.append(anExpression.charAt(position + 1));
304 result.append(anExpression.substring(previousPosition,
305 anExpression.length()));
307 return result.toString();