sorry forget these two Exceptions
[mir.git] / source / mir / config / ConfigReader.java
1 /*
2  * Copyright (C) 2001, 2002  The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
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.
10  *
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.
15  *
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
19  *
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.
30  */
31
32 package  mir.config;\r
33 \r
34 import java.io.File;
35 import java.io.FileInputStream;
36 import java.io.FileNotFoundException;
37 import java.io.IOException;
38 import java.util.HashMap;
39 import java.util.Map;
40 import java.util.Stack;
41
42 import javax.xml.parsers.ParserConfigurationException;
43 import javax.xml.parsers.SAXParser;
44 import javax.xml.parsers.SAXParserFactory;
45
46 import mir.config.exceptions.ConfigDefineNotKnownException;
47 import mir.config.exceptions.ConfigFailure;
48
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;
55 \r
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
65 \r
66   public ConfigReader() {\r
67     super();\r
68   };\r
69 \r
70   public void parseFile(String aFileName, ConfigNodeBuilder aRootNode) throws ConfigFailure {\r
71 \r
72     try {\r
73       SAXParserFactory parserFactory = SAXParserFactory.newInstance();\r
74 \r
75       parserFactory.setNamespaceAware(false);\r
76       parserFactory.setValidating(true);\r
77 \r
78 \r
79       ConfigReaderHandler handler = new ConfigReaderHandler(aRootNode, parserFactory);\r
80 \r
81       handler.includeFile(aFileName);\r
82     }\r
83     catch (Throwable e) {\r
84       if (e instanceof SAXParseException && ((SAXParseException) e).getException() instanceof ConfigFailure) {\r
85         throw (ConfigFailure) ((SAXParseException) e).getException();\r
86       }\r
87       else {\r
88         e.printStackTrace();\r
89         throw new ConfigFailure( e.getMessage() );\r
90       }\r
91     }\r
92   }\r
93 \r
94   private class ConfigReaderHandler extends DefaultHandler {\r
95     ConfigNodeBuilder builder;\r
96     Stack nodeStack;\r
97     Locator locator;\r
98     DefinesManager definesManager;\r
99     int level;\r
100     Stack includeFileStack;\r
101     SAXParserFactory parserFactory;\r
102 \r
103     public ConfigReaderHandler(ConfigNodeBuilder aBuilder, SAXParserFactory aParserFactory) {\r
104       super();\r
105 \r
106       builder=aBuilder;\r
107       nodeStack=new Stack();\r
108       includeFileStack=new Stack();\r
109       definesManager=new DefinesManager();\r
110       parserFactory=aParserFactory;\r
111       level=0;\r
112     }\r
113 \r
114     public String getLocatorDescription(Locator aLocator) {\r
115       return aLocator.getPublicId()+" ("+aLocator.getLineNumber()+")";\r
116     }\r
117 \r
118     public void setDocumentLocator(Locator aLocator) {\r
119       locator=aLocator;\r
120     }\r
121 \r
122     private void includeFile(String aFileName) throws ConfigFailure, SAXParseException, SAXException {\r
123       File file;\r
124       SAXParser parser;\r
125       InputSource inputSource;\r
126       System.err.println("about to include "+aFileName);\r
127 \r
128       try {\r
129         if (!includeFileStack.empty())\r
130           file = new File(new File((String) includeFileStack.peek()).getParent(), aFileName);\r
131         else\r
132           file = new File(aFileName);\r
133 \r
134         System.err.println("about to include "+file.getCanonicalPath());\r
135 \r
136         if (includeFileStack.contains(file.getCanonicalPath())) {\r
137           throw new ConfigFailure("recursive inclusion of file "+file.getCanonicalPath(), getLocatorDescription(locator));\r
138         }\r
139 \r
140         parser=parserFactory.newSAXParser();\r
141 \r
142         inputSource = new InputSource(new FileInputStream(file));\r
143         inputSource.setPublicId(file.getCanonicalPath());\r
144 \r
145         includeFileStack.push(file.getCanonicalPath());\r
146         try {\r
147           parser.parse(inputSource, this);\r
148         }\r
149         finally {\r
150           includeFileStack.pop();\r
151         }\r
152       }\r
153       catch (ParserConfigurationException e) {\r
154         throw new ConfigFailure("Internal exception while including \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));\r
155       }\r
156       catch (SAXParseException e) {\r
157         throw e;\r
158       }\r
159       catch (ConfigFailure e) {\r
160         throw e;\r
161       }\r
162       catch (FileNotFoundException e) {\r
163         throw new ConfigFailure("Include file \""+aFileName+"\" not found: "+e.getMessage(), e, getLocatorDescription(locator));\r
164       }\r
165       catch (IOException e) {\r
166         throw new ConfigFailure("unable to open include file \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));\r
167       }\r
168 \r
169     }\r
170 \r
171     public void startElement(String aUri, String aTag, String aQualifiedName, Attributes anAttributes) throws SAXException {\r
172       nodeStack.push(builder);\r
173       level++;\r
174       try {\r
175         if (builder==null) {\r
176           throw new ConfigFailure("define, include and property tags cannot have content", getLocatorDescription(locator));\r
177         }\r
178         if (aQualifiedName.equals(propertyTagName)) {\r
179           String name=anAttributes.getValue(propertyNameAttribute);\r
180           String value=anAttributes.getValue(propertyValueAttribute);\r
181 \r
182           if (name==null) {\r
183             throw new ConfigFailure("property has no name attribute", getLocatorDescription(locator));\r
184           }\r
185           else\r
186           if (value==null) {\r
187             throw new ConfigFailure("property \""+name+"\" has no value attribute", getLocatorDescription(locator));\r
188           }\r
189 \r
190           builder.addProperty(name, definesManager.resolve(value, getLocatorDescription(locator)), value, getLocatorDescription(locator));\r
191           builder=null;\r
192 \r
193         }\r
194         else if (aQualifiedName.equals(defineTagName)) {\r
195           String name=anAttributes.getValue(defineNameAttribute);\r
196           String value=anAttributes.getValue(defineValueAttribute);\r
197 \r
198           if (name==null) {\r
199             throw new ConfigFailure("define has no name attribute", getLocatorDescription(locator));\r
200           }\r
201           else\r
202           if (value==null) {\r
203             throw new ConfigFailure("define \""+name+"\" has no value attribute", getLocatorDescription(locator));\r
204           }\r
205 \r
206           definesManager.addDefine(name, definesManager.resolve(value, getLocatorDescription(locator)));\r
207           builder=null;\r
208         }\r
209         else if (aQualifiedName.equals(includeTagName)) {\r
210           String fileName=anAttributes.getValue(includeFileAttribute);\r
211 \r
212           if (fileName==null) {\r
213             throw new ConfigFailure("include has no file attribute", getLocatorDescription(locator));\r
214           }\r
215 \r
216           includeFile(definesManager.resolve(fileName, getLocatorDescription(locator)));\r
217           builder=null;\r
218         }\r
219         else\r
220         {\r
221           builder=builder.makeSubNode(aQualifiedName, getLocatorDescription(locator));\r
222         }\r
223       }\r
224       catch (ConfigFailure e) {\r
225         throw new SAXParseException(e.getMessage(), locator, e);\r
226       }\r
227     }\r
228 \r
229     public void endElement(String aUri, String aTag, String aQualifiedName) throws SAXParseException {\r
230       builder=(ConfigNodeBuilder) nodeStack.pop();\r
231       level--;\r
232     }\r
233 \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
238       }\r
239     }\r
240   }\r
241 \r
242   private class DefinesManager {\r
243     Map defines;\r
244 \r
245     public DefinesManager() {\r
246       defines = new HashMap();\r
247     }\r
248 \r
249     public void addDefine(String aName, String anExpression) {\r
250       defines.put(aName, anExpression);\r
251     }\r
252 \r
253     public String resolve(String anExpression, String aLocation) throws ConfigFailure {\r
254       int previousPosition = 0;\r
255       int position;\r
256       int endOfNamePosition;\r
257       String name;\r
258 \r
259       StringBuffer result = new StringBuffer();\r
260 \r
261       while ((position=anExpression.indexOf("$", previousPosition))>=0) {\r
262         result.append(anExpression.substring(previousPosition, position));\r
263 \r
264         if (position>=anExpression.length()-1) {\r
265           result.append(anExpression.substring(position, anExpression.length()));\r
266           previousPosition=anExpression.length();\r
267         }\r
268         else\r
269         {\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
277               }\r
278               else {\r
279                 throw new ConfigDefineNotKnownException("Variable \""+name+"\" not defined", aLocation);\r
280               }\r
281             }\r
282             else {\r
283                 throw new ConfigFailure("Missing }", aLocation);\r
284             }\r
285 \r
286           }\r
287           else\r
288           {\r
289             previousPosition=position+2;\r
290             result.append(anExpression.charAt(position+1));\r
291           }\r
292         }\r
293       }\r
294       result.append(anExpression.substring(previousPosition, anExpression.length()));\r
295 \r
296       return result.toString();\r
297     }\r
298   }\r
299 }\r
300 \r
301 \r