5 import java.lang.System;
\r
6 import org.xml.sax.helpers.DefaultHandler;
\r
7 import org.xml.sax.*;
\r
8 import javax.xml.parsers.ParserConfigurationException;
\r
9 import javax.xml.parsers.SAXParser;
\r
10 import javax.xml.parsers.SAXParserFactory;
\r
12 import mir.config.exceptions.*;
\r
13 import mir.misc.Location;
\r
15 public class ConfigReader {
\r
16 final static String propertyTagName="property";
\r
17 final static String propertyNameAttribute="name";
\r
18 final static String propertyValueAttribute="value";
\r
19 final static String defineTagName="define";
\r
20 final static String defineNameAttribute="name";
\r
21 final static String defineValueAttribute="value";
\r
22 final static String includeTagName="include";
\r
23 final static String includeFileAttribute="file";
\r
25 public ConfigReader() {
\r
29 public void parseFile(String aFileName, ConfigNodeBuilder aRootNode) throws ConfigFailure {
\r
32 SAXParserFactory parserFactory = SAXParserFactory.newInstance();
\r
34 parserFactory.setNamespaceAware(false);
\r
35 parserFactory.setValidating(true);
\r
38 ConfigReaderHandler handler = new ConfigReaderHandler(aRootNode, parserFactory);
\r
40 handler.includeFile(aFileName);
\r
42 catch (Throwable e) {
\r
43 if (e instanceof SAXParseException && ((SAXParseException) e).getException() instanceof ConfigFailure) {
\r
44 throw (ConfigFailure) ((SAXParseException) e).getException();
\r
47 e.printStackTrace();
\r
48 throw new ConfigFailure( e.getMessage() );
\r
53 private class ConfigReaderHandler extends DefaultHandler {
\r
54 ConfigNodeBuilder builder;
\r
57 DefinesManager definesManager;
\r
59 Stack includeFileStack;
\r
60 SAXParserFactory parserFactory;
\r
62 public ConfigReaderHandler(ConfigNodeBuilder aBuilder, SAXParserFactory aParserFactory) {
\r
66 nodeStack=new Stack();
\r
67 includeFileStack=new Stack();
\r
68 definesManager=new DefinesManager();
\r
69 parserFactory=aParserFactory;
\r
73 public String getLocatorDescription(Locator aLocator) {
\r
74 return aLocator.getPublicId()+" ("+aLocator.getLineNumber()+")";
\r
77 public void setDocumentLocator(Locator aLocator) {
\r
81 private void includeFile(String aFileName) throws ConfigFailure, SAXParseException, SAXException {
\r
84 InputSource inputSource;
\r
85 System.err.println("about to include "+aFileName);
\r
88 if (!includeFileStack.empty())
\r
89 file = new File(new File((String) includeFileStack.peek()).getParent(), aFileName);
\r
91 file = new File(aFileName);
\r
93 System.err.println("about to include "+file.getCanonicalPath());
\r
95 if (includeFileStack.contains(file.getCanonicalPath())) {
\r
96 throw new ConfigFailure("recursive inclusion of file "+file.getCanonicalPath(), getLocatorDescription(locator));
\r
99 parser=parserFactory.newSAXParser();
\r
101 inputSource = new InputSource(new FileInputStream(file));
\r
102 inputSource.setPublicId(file.getCanonicalPath());
\r
104 includeFileStack.push(file.getCanonicalPath());
\r
106 parser.parse(inputSource, this);
\r
109 includeFileStack.pop();
\r
112 catch (ParserConfigurationException e) {
\r
113 throw new ConfigFailure("Internal exception while including \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));
\r
115 catch (SAXParseException e) {
\r
118 catch (ConfigFailure e) {
\r
121 catch (FileNotFoundException e) {
\r
122 throw new ConfigFailure("Include file \""+aFileName+"\" not found: "+e.getMessage(), e, getLocatorDescription(locator));
\r
124 catch (IOException e) {
\r
125 throw new ConfigFailure("unable to open include file \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));
\r
130 public void startElement(String aUri, String aTag, String aQualifiedName, Attributes anAttributes) throws SAXException {
\r
131 nodeStack.push(builder);
\r
134 if (builder==null) {
\r
135 throw new ConfigFailure("define, include and property tags cannot have content", getLocatorDescription(locator));
\r
137 if (aQualifiedName.equals(propertyTagName)) {
\r
138 String name=anAttributes.getValue(propertyNameAttribute);
\r
139 String value=anAttributes.getValue(propertyValueAttribute);
\r
142 throw new ConfigFailure("property has no name attribute", getLocatorDescription(locator));
\r
146 throw new ConfigFailure("property \""+name+"\" has no value attribute", getLocatorDescription(locator));
\r
149 builder.addProperty(name, definesManager.resolve(value, getLocatorDescription(locator)), value, getLocatorDescription(locator));
\r
153 else if (aQualifiedName.equals(defineTagName)) {
\r
154 String name=anAttributes.getValue(defineNameAttribute);
\r
155 String value=anAttributes.getValue(defineValueAttribute);
\r
158 throw new ConfigFailure("define has no name attribute", getLocatorDescription(locator));
\r
162 throw new ConfigFailure("define \""+name+"\" has no value attribute", getLocatorDescription(locator));
\r
165 definesManager.addDefine(name, definesManager.resolve(value, getLocatorDescription(locator)));
\r
168 else if (aQualifiedName.equals(includeTagName)) {
\r
169 String fileName=anAttributes.getValue(includeFileAttribute);
\r
171 if (fileName==null) {
\r
172 throw new ConfigFailure("include has no file attribute", getLocatorDescription(locator));
\r
175 includeFile(definesManager.resolve(fileName, getLocatorDescription(locator)));
\r
180 builder=builder.makeSubNode(aQualifiedName, getLocatorDescription(locator));
\r
183 catch (ConfigFailure e) {
\r
184 throw new SAXParseException(e.getMessage(), locator, e);
\r
188 public void endElement(String aUri, String aTag, String aQualifiedName) throws SAXParseException {
\r
189 builder=(ConfigNodeBuilder) nodeStack.pop();
\r
193 public void characters(char[] aBuffer, int aStart, int anEnd) throws SAXParseException {
\r
194 String text = new String(aBuffer, aStart, anEnd).trim();
\r
195 if ( text.length() > 0) {
\r
196 throw new SAXParseException("Text not allowed", locator, new ConfigFailure("text not allowed", getLocatorDescription(locator)));
\r
201 private class DefinesManager {
\r
204 public DefinesManager() {
\r
205 defines = new HashMap();
\r
208 public void addDefine(String aName, String anExpression) {
\r
209 defines.put(aName, anExpression);
\r
212 public String resolve(String anExpression, String aLocation) throws ConfigFailure {
\r
213 int previousPosition = 0;
\r
215 int endOfNamePosition;
\r
218 StringBuffer result = new StringBuffer();
\r
220 while ((position=anExpression.indexOf("$", previousPosition))>=0) {
\r
221 result.append(anExpression.substring(previousPosition, position));
\r
223 if (position>=anExpression.length()-1) {
\r
224 result.append(anExpression.substring(position, anExpression.length()));
\r
225 previousPosition=anExpression.length();
\r
229 if (anExpression.charAt(position+1) == '{') {
\r
230 endOfNamePosition=anExpression.indexOf('}', position);
\r
231 if (endOfNamePosition>=0) {
\r
232 name=anExpression.substring(position+2, endOfNamePosition);
\r
233 if (defines.containsKey(name)) {
\r
234 result.append((String) defines.get(name));
\r
235 previousPosition=endOfNamePosition+1;
\r
238 throw new ConfigDefineNotKnownException("Variable \""+name+"\" not defined", aLocation);
\r
242 throw new ConfigFailure("Missing }", aLocation);
\r
248 previousPosition=position+2;
\r
249 result.append(anExpression.charAt(position+1));
\r
253 result.append(anExpression.substring(previousPosition, anExpression.length()));
\r
255 return result.toString();
\r