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.
36 import java.lang.System;
\r
37 import org.xml.sax.helpers.DefaultHandler;
\r
38 import org.xml.sax.*;
\r
39 import javax.xml.parsers.ParserConfigurationException;
\r
40 import javax.xml.parsers.SAXParser;
\r
41 import javax.xml.parsers.SAXParserFactory;
\r
43 import mir.config.exceptions.*;
\r
44 import mir.misc.Location;
\r
46 public class ConfigReader {
\r
47 final static String propertyTagName="property";
\r
48 final static String propertyNameAttribute="name";
\r
49 final static String propertyValueAttribute="value";
\r
50 final static String defineTagName="define";
\r
51 final static String defineNameAttribute="name";
\r
52 final static String defineValueAttribute="value";
\r
53 final static String includeTagName="include";
\r
54 final static String includeFileAttribute="file";
\r
56 public ConfigReader() {
\r
60 public void parseFile(String aFileName, ConfigNodeBuilder aRootNode) throws ConfigFailure {
\r
63 SAXParserFactory parserFactory = SAXParserFactory.newInstance();
\r
65 parserFactory.setNamespaceAware(false);
\r
66 parserFactory.setValidating(true);
\r
69 ConfigReaderHandler handler = new ConfigReaderHandler(aRootNode, parserFactory);
\r
71 handler.includeFile(aFileName);
\r
73 catch (Throwable e) {
\r
74 if (e instanceof SAXParseException && ((SAXParseException) e).getException() instanceof ConfigFailure) {
\r
75 throw (ConfigFailure) ((SAXParseException) e).getException();
\r
78 e.printStackTrace();
\r
79 throw new ConfigFailure( e.getMessage() );
\r
84 private class ConfigReaderHandler extends DefaultHandler {
\r
85 ConfigNodeBuilder builder;
\r
88 DefinesManager definesManager;
\r
90 Stack includeFileStack;
\r
91 SAXParserFactory parserFactory;
\r
93 public ConfigReaderHandler(ConfigNodeBuilder aBuilder, SAXParserFactory aParserFactory) {
\r
97 nodeStack=new Stack();
\r
98 includeFileStack=new Stack();
\r
99 definesManager=new DefinesManager();
\r
100 parserFactory=aParserFactory;
\r
104 public String getLocatorDescription(Locator aLocator) {
\r
105 return aLocator.getPublicId()+" ("+aLocator.getLineNumber()+")";
\r
108 public void setDocumentLocator(Locator aLocator) {
\r
112 private void includeFile(String aFileName) throws ConfigFailure, SAXParseException, SAXException {
\r
115 InputSource inputSource;
\r
116 System.err.println("about to include "+aFileName);
\r
119 if (!includeFileStack.empty())
\r
120 file = new File(new File((String) includeFileStack.peek()).getParent(), aFileName);
\r
122 file = new File(aFileName);
\r
124 System.err.println("about to include "+file.getCanonicalPath());
\r
126 if (includeFileStack.contains(file.getCanonicalPath())) {
\r
127 throw new ConfigFailure("recursive inclusion of file "+file.getCanonicalPath(), getLocatorDescription(locator));
\r
130 parser=parserFactory.newSAXParser();
\r
132 inputSource = new InputSource(new FileInputStream(file));
\r
133 inputSource.setPublicId(file.getCanonicalPath());
\r
135 includeFileStack.push(file.getCanonicalPath());
\r
137 parser.parse(inputSource, this);
\r
140 includeFileStack.pop();
\r
143 catch (ParserConfigurationException e) {
\r
144 throw new ConfigFailure("Internal exception while including \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));
\r
146 catch (SAXParseException e) {
\r
149 catch (ConfigFailure e) {
\r
152 catch (FileNotFoundException e) {
\r
153 throw new ConfigFailure("Include file \""+aFileName+"\" not found: "+e.getMessage(), e, getLocatorDescription(locator));
\r
155 catch (IOException e) {
\r
156 throw new ConfigFailure("unable to open include file \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));
\r
161 public void startElement(String aUri, String aTag, String aQualifiedName, Attributes anAttributes) throws SAXException {
\r
162 nodeStack.push(builder);
\r
165 if (builder==null) {
\r
166 throw new ConfigFailure("define, include and property tags cannot have content", getLocatorDescription(locator));
\r
168 if (aQualifiedName.equals(propertyTagName)) {
\r
169 String name=anAttributes.getValue(propertyNameAttribute);
\r
170 String value=anAttributes.getValue(propertyValueAttribute);
\r
173 throw new ConfigFailure("property has no name attribute", getLocatorDescription(locator));
\r
177 throw new ConfigFailure("property \""+name+"\" has no value attribute", getLocatorDescription(locator));
\r
180 builder.addProperty(name, definesManager.resolve(value, getLocatorDescription(locator)), value, getLocatorDescription(locator));
\r
184 else if (aQualifiedName.equals(defineTagName)) {
\r
185 String name=anAttributes.getValue(defineNameAttribute);
\r
186 String value=anAttributes.getValue(defineValueAttribute);
\r
189 throw new ConfigFailure("define has no name attribute", getLocatorDescription(locator));
\r
193 throw new ConfigFailure("define \""+name+"\" has no value attribute", getLocatorDescription(locator));
\r
196 definesManager.addDefine(name, definesManager.resolve(value, getLocatorDescription(locator)));
\r
199 else if (aQualifiedName.equals(includeTagName)) {
\r
200 String fileName=anAttributes.getValue(includeFileAttribute);
\r
202 if (fileName==null) {
\r
203 throw new ConfigFailure("include has no file attribute", getLocatorDescription(locator));
\r
206 includeFile(definesManager.resolve(fileName, getLocatorDescription(locator)));
\r
211 builder=builder.makeSubNode(aQualifiedName, getLocatorDescription(locator));
\r
214 catch (ConfigFailure e) {
\r
215 throw new SAXParseException(e.getMessage(), locator, e);
\r
219 public void endElement(String aUri, String aTag, String aQualifiedName) throws SAXParseException {
\r
220 builder=(ConfigNodeBuilder) nodeStack.pop();
\r
224 public void characters(char[] aBuffer, int aStart, int anEnd) throws SAXParseException {
\r
225 String text = new String(aBuffer, aStart, anEnd).trim();
\r
226 if ( text.length() > 0) {
\r
227 throw new SAXParseException("Text not allowed", locator, new ConfigFailure("text not allowed", getLocatorDescription(locator)));
\r
232 private class DefinesManager {
\r
235 public DefinesManager() {
\r
236 defines = new HashMap();
\r
239 public void addDefine(String aName, String anExpression) {
\r
240 defines.put(aName, anExpression);
\r
243 public String resolve(String anExpression, String aLocation) throws ConfigFailure {
\r
244 int previousPosition = 0;
\r
246 int endOfNamePosition;
\r
249 StringBuffer result = new StringBuffer();
\r
251 while ((position=anExpression.indexOf("$", previousPosition))>=0) {
\r
252 result.append(anExpression.substring(previousPosition, position));
\r
254 if (position>=anExpression.length()-1) {
\r
255 result.append(anExpression.substring(position, anExpression.length()));
\r
256 previousPosition=anExpression.length();
\r
260 if (anExpression.charAt(position+1) == '{') {
\r
261 endOfNamePosition=anExpression.indexOf('}', position);
\r
262 if (endOfNamePosition>=0) {
\r
263 name=anExpression.substring(position+2, endOfNamePosition);
\r
264 if (defines.containsKey(name)) {
\r
265 result.append((String) defines.get(name));
\r
266 previousPosition=endOfNamePosition+1;
\r
269 throw new ConfigDefineNotKnownException("Variable \""+name+"\" not defined", aLocation);
\r
273 throw new ConfigFailure("Missing }", aLocation);
\r
279 previousPosition=position+2;
\r
280 result.append(anExpression.charAt(position+1));
\r
284 result.append(anExpression.substring(previousPosition, anExpression.length()));
\r
286 return result.toString();
\r