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.
35 import java.io.FileInputStream;
36 import java.io.FileNotFoundException;
37 import java.io.IOException;
38 import java.util.HashMap;
40 import java.util.Stack;
42 import javax.xml.parsers.ParserConfigurationException;
43 import javax.xml.parsers.SAXParser;
44 import javax.xml.parsers.SAXParserFactory;
46 import mir.config.exceptions.ConfigDefineNotKnownException;
47 import mir.config.exceptions.ConfigFailure;
49 import org.xml.sax.Attributes;
50 import org.xml.sax.InputSource;
51 import org.xml.sax.Locator;
52 import org.xml.sax.SAXException;
53 import org.xml.sax.SAXParseException;
54 import org.xml.sax.helpers.DefaultHandler;
56 public class ConfigReader {
\r
57 final static String propertyTagName="property";
\r
58 final static String propertyNameAttribute="name";
\r
59 final static String propertyValueAttribute="value";
\r
60 final static String defineTagName="define";
\r
61 final static String defineNameAttribute="name";
\r
62 final static String defineValueAttribute="value";
\r
63 final static String includeTagName="include";
\r
64 final static String includeFileAttribute="file";
\r
66 public ConfigReader() {
\r
70 public void parseFile(String aFileName, ConfigNodeBuilder aRootNode) throws ConfigFailure {
\r
73 SAXParserFactory parserFactory = SAXParserFactory.newInstance();
\r
75 parserFactory.setNamespaceAware(false);
\r
76 parserFactory.setValidating(true);
\r
79 ConfigReaderHandler handler = new ConfigReaderHandler(aRootNode, parserFactory);
\r
81 handler.includeFile(aFileName);
\r
83 catch (Throwable e) {
\r
84 if (e instanceof SAXParseException && ((SAXParseException) e).getException() instanceof ConfigFailure) {
\r
85 throw (ConfigFailure) ((SAXParseException) e).getException();
\r
88 e.printStackTrace();
\r
89 throw new ConfigFailure( e.getMessage() );
\r
94 private class ConfigReaderHandler extends DefaultHandler {
\r
95 ConfigNodeBuilder builder;
\r
98 DefinesManager definesManager;
\r
100 Stack includeFileStack;
\r
101 SAXParserFactory parserFactory;
\r
103 public ConfigReaderHandler(ConfigNodeBuilder aBuilder, SAXParserFactory aParserFactory) {
\r
107 nodeStack=new Stack();
\r
108 includeFileStack=new Stack();
\r
109 definesManager=new DefinesManager();
\r
110 parserFactory=aParserFactory;
\r
114 public String getLocatorDescription(Locator aLocator) {
\r
115 return aLocator.getPublicId()+" ("+aLocator.getLineNumber()+")";
\r
118 public void setDocumentLocator(Locator aLocator) {
\r
122 private void includeFile(String aFileName) throws ConfigFailure, SAXParseException, SAXException {
\r
125 InputSource inputSource;
\r
126 System.err.println("about to include "+aFileName);
\r
129 if (!includeFileStack.empty())
\r
130 file = new File(new File((String) includeFileStack.peek()).getParent(), aFileName);
\r
132 file = new File(aFileName);
\r
134 System.err.println("about to include "+file.getCanonicalPath());
\r
136 if (includeFileStack.contains(file.getCanonicalPath())) {
\r
137 throw new ConfigFailure("recursive inclusion of file "+file.getCanonicalPath(), getLocatorDescription(locator));
\r
140 parser=parserFactory.newSAXParser();
\r
142 inputSource = new InputSource(new FileInputStream(file));
\r
143 inputSource.setPublicId(file.getCanonicalPath());
\r
145 includeFileStack.push(file.getCanonicalPath());
\r
147 parser.parse(inputSource, this);
\r
150 includeFileStack.pop();
\r
153 catch (ParserConfigurationException e) {
\r
154 throw new ConfigFailure("Internal exception while including \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));
\r
156 catch (SAXParseException e) {
\r
159 catch (ConfigFailure e) {
\r
162 catch (FileNotFoundException e) {
\r
163 throw new ConfigFailure("Include file \""+aFileName+"\" not found: "+e.getMessage(), e, getLocatorDescription(locator));
\r
165 catch (IOException e) {
\r
166 throw new ConfigFailure("unable to open include file \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));
\r
171 public void startElement(String aUri, String aTag, String aQualifiedName, Attributes anAttributes) throws SAXException {
\r
172 nodeStack.push(builder);
\r
175 if (builder==null) {
\r
176 throw new ConfigFailure("define, include and property tags cannot have content", getLocatorDescription(locator));
\r
178 if (aQualifiedName.equals(propertyTagName)) {
\r
179 String name=anAttributes.getValue(propertyNameAttribute);
\r
180 String value=anAttributes.getValue(propertyValueAttribute);
\r
183 throw new ConfigFailure("property has no name attribute", getLocatorDescription(locator));
\r
187 throw new ConfigFailure("property \""+name+"\" has no value attribute", getLocatorDescription(locator));
\r
190 builder.addProperty(name, definesManager.resolve(value, getLocatorDescription(locator)), value, getLocatorDescription(locator));
\r
194 else if (aQualifiedName.equals(defineTagName)) {
\r
195 String name=anAttributes.getValue(defineNameAttribute);
\r
196 String value=anAttributes.getValue(defineValueAttribute);
\r
199 throw new ConfigFailure("define has no name attribute", getLocatorDescription(locator));
\r
203 throw new ConfigFailure("define \""+name+"\" has no value attribute", getLocatorDescription(locator));
\r
206 definesManager.addDefine(name, definesManager.resolve(value, getLocatorDescription(locator)));
\r
209 else if (aQualifiedName.equals(includeTagName)) {
\r
210 String fileName=anAttributes.getValue(includeFileAttribute);
\r
212 if (fileName==null) {
\r
213 throw new ConfigFailure("include has no file attribute", getLocatorDescription(locator));
\r
216 includeFile(definesManager.resolve(fileName, getLocatorDescription(locator)));
\r
221 builder=builder.makeSubNode(aQualifiedName, getLocatorDescription(locator));
\r
224 catch (ConfigFailure e) {
\r
225 throw new SAXParseException(e.getMessage(), locator, e);
\r
229 public void endElement(String aUri, String aTag, String aQualifiedName) throws SAXParseException {
\r
230 builder=(ConfigNodeBuilder) nodeStack.pop();
\r
234 public void characters(char[] aBuffer, int aStart, int anEnd) throws SAXParseException {
\r
235 String text = new String(aBuffer, aStart, anEnd).trim();
\r
236 if ( text.length() > 0) {
\r
237 throw new SAXParseException("Text not allowed", locator, new ConfigFailure("text not allowed", getLocatorDescription(locator)));
\r
242 private class DefinesManager {
\r
245 public DefinesManager() {
\r
246 defines = new HashMap();
\r
249 public void addDefine(String aName, String anExpression) {
\r
250 defines.put(aName, anExpression);
\r
253 public String resolve(String anExpression, String aLocation) throws ConfigFailure {
\r
254 int previousPosition = 0;
\r
256 int endOfNamePosition;
\r
259 StringBuffer result = new StringBuffer();
\r
261 while ((position=anExpression.indexOf("$", previousPosition))>=0) {
\r
262 result.append(anExpression.substring(previousPosition, position));
\r
264 if (position>=anExpression.length()-1) {
\r
265 result.append(anExpression.substring(position, anExpression.length()));
\r
266 previousPosition=anExpression.length();
\r
270 if (anExpression.charAt(position+1) == '{') {
\r
271 endOfNamePosition=anExpression.indexOf('}', position);
\r
272 if (endOfNamePosition>=0) {
\r
273 name=anExpression.substring(position+2, endOfNamePosition);
\r
274 if (defines.containsKey(name)) {
\r
275 result.append((String) defines.get(name));
\r
276 previousPosition=endOfNamePosition+1;
\r
279 throw new ConfigDefineNotKnownException("Variable \""+name+"\" not defined", aLocation);
\r
283 throw new ConfigFailure("Missing }", aLocation);
\r
289 previousPosition=position+2;
\r
290 result.append(anExpression.charAt(position+1));
\r
294 result.append(anExpression.substring(previousPosition, anExpression.length()));
\r
296 return result.toString();
\r