03ecd5329db8861b6fbffb29c87dfb901e11c26e
[mir.git] / source / mir / config / ConfigReader.java
1 package  mir.config;\r
2 \r
3 import java.io.*;\r
4 import java.util.*;\r
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
11 \r
12 import mir.config.exceptions.*;\r
13 import mir.misc.Location;\r
14 \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
24 \r
25   public ConfigReader() {\r
26     super();\r
27   };\r
28 \r
29   public void parseFile(String aFileName, ConfigNodeBuilder aRootNode) throws ConfigException {\r
30 \r
31     try {\r
32       SAXParserFactory parserFactory = SAXParserFactory.newInstance();\r
33 \r
34       parserFactory.setNamespaceAware(false);\r
35       parserFactory.setValidating(true);\r
36 \r
37 \r
38       ConfigReaderHandler handler = new ConfigReaderHandler(aRootNode, parserFactory);\r
39 \r
40       handler.includeFile(aFileName);\r
41     }\r
42     catch (Throwable e) {\r
43       if (e instanceof SAXParseException && ((SAXParseException) e).getException() instanceof ConfigException) {\r
44         throw (ConfigException) ((SAXParseException) e).getException();\r
45       }\r
46       else {\r
47         e.printStackTrace();\r
48         throw new ConfigException( e.getMessage() );\r
49       }\r
50     }\r
51   }\r
52 \r
53   private class ConfigReaderHandler extends DefaultHandler {\r
54     ConfigNodeBuilder builder;\r
55     Stack nodeStack;\r
56     Locator locator;\r
57     DefinesManager definesManager;\r
58     int level;\r
59     Stack includeFileStack;\r
60     SAXParserFactory parserFactory;\r
61 \r
62     public ConfigReaderHandler(ConfigNodeBuilder aBuilder, SAXParserFactory aParserFactory) {\r
63       super();\r
64 \r
65       builder=aBuilder;\r
66       nodeStack=new Stack();\r
67       includeFileStack=new Stack();\r
68       definesManager=new DefinesManager();\r
69       parserFactory=aParserFactory;\r
70       level=0;\r
71     }\r
72 \r
73     public String getLocatorDescription(Locator aLocator) {\r
74       return aLocator.getPublicId()+" ("+aLocator.getLineNumber()+")";\r
75     }\r
76 \r
77     public void setDocumentLocator(Locator aLocator) {\r
78       locator=aLocator;\r
79     }\r
80 \r
81     private void includeFile(String aFileName) throws ConfigException, SAXParseException, SAXException {\r
82       File file;\r
83       SAXParser parser;\r
84       InputSource inputSource;\r
85       System.err.println("about to include "+aFileName);\r
86 \r
87       try {\r
88         if (!includeFileStack.empty())\r
89           file = new File(new File((String) includeFileStack.peek()).getParent(), aFileName);\r
90         else\r
91           file = new File(aFileName);\r
92 \r
93         System.err.println("about to include "+file.getCanonicalPath());\r
94 \r
95         if (includeFileStack.contains(file.getCanonicalPath())) {\r
96           throw new ConfigException("recursive inclusion of file "+file.getCanonicalPath(), getLocatorDescription(locator));\r
97         }\r
98 \r
99         parser=parserFactory.newSAXParser();\r
100 \r
101         inputSource = new InputSource(new FileInputStream(file));\r
102         inputSource.setPublicId(file.getCanonicalPath());\r
103 \r
104         includeFileStack.push(file.getCanonicalPath());\r
105         try {\r
106           parser.parse(inputSource, this);\r
107         }\r
108         finally {\r
109           includeFileStack.pop();\r
110         }\r
111       }\r
112       catch (ParserConfigurationException e) {\r
113         throw new ConfigException("Internal exception while including \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));\r
114       }\r
115       catch (SAXParseException e) {\r
116         throw e;\r
117       }\r
118       catch (ConfigException e) {\r
119         throw e;\r
120       }\r
121       catch (FileNotFoundException e) {\r
122         throw new ConfigException("Include file \""+aFileName+"\" not found: "+e.getMessage(), e, getLocatorDescription(locator));\r
123       }\r
124       catch (IOException e) {\r
125         throw new ConfigException("unable to open include file \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));\r
126       }\r
127 \r
128     }\r
129 \r
130     public void startElement(String aUri, String aTag, String aQualifiedName, Attributes anAttributes) throws SAXException {\r
131       nodeStack.push(builder);\r
132       level++;\r
133       try {\r
134         if (builder==null) {\r
135           throw new ConfigException("define, include and property tags cannot have content", getLocatorDescription(locator));\r
136         }\r
137         if (aQualifiedName.equals(propertyTagName)) {\r
138           String name=anAttributes.getValue(propertyNameAttribute);\r
139           String value=anAttributes.getValue(propertyValueAttribute);\r
140 \r
141           if (name==null) {\r
142             throw new ConfigException("property has no name attribute", getLocatorDescription(locator));\r
143           }\r
144           else\r
145           if (value==null) {\r
146             throw new ConfigException("property \""+name+"\" has no value attribute", getLocatorDescription(locator));\r
147           }\r
148 \r
149           builder.addProperty(name, definesManager.resolve(value, getLocatorDescription(locator)), value, getLocatorDescription(locator));\r
150           builder=null;\r
151 \r
152         }\r
153         else if (aQualifiedName.equals(defineTagName)) {\r
154           String name=anAttributes.getValue(defineNameAttribute);\r
155           String value=anAttributes.getValue(defineValueAttribute);\r
156 \r
157           if (name==null) {\r
158             throw new ConfigException("define has no name attribute", getLocatorDescription(locator));\r
159           }\r
160           else\r
161           if (value==null) {\r
162             throw new ConfigException("define \""+name+"\" has no value attribute", getLocatorDescription(locator));\r
163           }\r
164 \r
165           definesManager.addDefine(name, definesManager.resolve(value, getLocatorDescription(locator)));\r
166           builder=null;\r
167         }\r
168         else if (aQualifiedName.equals(includeTagName)) {\r
169           String fileName=anAttributes.getValue(includeFileAttribute);\r
170 \r
171           if (fileName==null) {\r
172             throw new ConfigException("include has no file attribute", getLocatorDescription(locator));\r
173           }\r
174 \r
175           includeFile(definesManager.resolve(fileName, getLocatorDescription(locator)));\r
176           builder=null;\r
177         }\r
178         else\r
179         {\r
180           builder=builder.makeSubNode(aQualifiedName, getLocatorDescription(locator));\r
181         }\r
182       }\r
183       catch (ConfigException e) {\r
184         throw new SAXParseException(e.getMessage(), locator, e);\r
185       }\r
186     }\r
187 \r
188     public void endElement(String aUri, String aTag, String aQualifiedName) throws SAXParseException {\r
189       builder=(ConfigNodeBuilder) nodeStack.pop();\r
190       level--;\r
191     }\r
192 \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 ConfigException("text not allowed", getLocatorDescription(locator)));\r
197       }\r
198     }\r
199   }\r
200 \r
201   private class DefinesManager {\r
202     Map defines;\r
203 \r
204     public DefinesManager() {\r
205       defines = new HashMap();\r
206     }\r
207 \r
208     public void addDefine(String aName, String anExpression) {\r
209       defines.put(aName, anExpression);\r
210     }\r
211 \r
212     public String resolve(String anExpression, String aLocation) throws ConfigException {\r
213       int previousPosition = 0;\r
214       int position;\r
215       int endOfNamePosition;\r
216       String name;\r
217 \r
218       StringBuffer result = new StringBuffer();\r
219 \r
220       while ((position=anExpression.indexOf("$", previousPosition))>=0) {\r
221         result.append(anExpression.substring(previousPosition, position));\r
222 \r
223         if (position>=anExpression.length()-1) {\r
224           result.append(anExpression.substring(position, anExpression.length()));\r
225           previousPosition=anExpression.length();\r
226         }\r
227         else\r
228         {\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
236               }\r
237               else {\r
238                 throw new ConfigDefineNotKnownException("Variable \""+name+"\" not defined", aLocation);\r
239               }\r
240             }\r
241             else {\r
242                 throw new ConfigException("Missing }", aLocation);\r
243             }\r
244 \r
245           }\r
246           else\r
247           {\r
248             previousPosition=position+2;\r
249             result.append(anExpression.charAt(position+1));\r
250           }\r
251         }\r
252       }\r
253       result.append(anExpression.substring(previousPosition, anExpression.length()));\r
254 \r
255       return result.toString();\r
256     }\r
257   }\r
258 }\r
259 \r
260 \r