001: /*--
002:
003: Copyright (C) 2000-2003 Anthony Eden.
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009:
010: 1. Redistributions of source code must retain the above copyright
011: notice, this list of conditions, and the following disclaimer.
012:
013: 2. Redistributions in binary form must reproduce the above copyright
014: notice, this list of conditions, and the disclaimer that follows
015: these conditions in the documentation and/or other materials
016: provided with the distribution.
017:
018: 3. The name "EdenLib" must not be used to endorse or promote products
019: derived from this software without prior written permission. For
020: written permission, please contact me@anthonyeden.com.
021:
022: 4. Products derived from this software may not be called "EdenLib", nor
023: may "EdenLib" appear in their name, without prior written permission
024: from Anthony Eden (me@anthonyeden.com).
025:
026: In addition, I request (but do not require) that you include in the
027: end-user documentation provided with the redistribution and/or in the
028: software itself an acknowledgement equivalent to the following:
029: "This product includes software developed by
030: Anthony Eden (http://www.anthonyeden.com/)."
031:
032: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
033: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
034: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
035: DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
036: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
037: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
038: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
039: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
040: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
041: IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
042: POSSIBILITY OF SUCH DAMAGE.
043:
044: For more information on EdenLib, please see <http://edenlib.sf.net/>.
045:
046: */
047:
048: package com.anthonyeden.lib.config.sax;
049:
050: import com.anthonyeden.lib.config.Configuration;
051: import com.anthonyeden.lib.config.ConfigurationBase;
052: import com.anthonyeden.lib.config.ConfigurationException;
053: import com.anthonyeden.lib.config.ConfigurationFactory;
054: import com.anthonyeden.lib.util.ClassUtilities;
055: import com.anthonyeden.lib.util.IOUtilities;
056: import com.anthonyeden.lib.util.MessageUtilities;
057: import org.apache.commons.logging.Log;
058: import org.apache.commons.logging.LogFactory;
059: import org.xml.sax.InputSource;
060: import org.xml.sax.SAXException;
061: import org.xml.sax.XMLReader;
062: import org.xml.sax.helpers.XMLReaderFactory;
063:
064: import java.io.*;
065: import java.util.Properties;
066:
067: /**
068: * Implementation of the ConfigurationFactory interface which generates a
069: * a configuration tree using a SAX parser.
070: * <p/>
071: * -fixed the unicode parsing [Florin]
072: *
073: * @author Anthony Eden
074: * @author <a href="mailto:florin.patrascu@gmail.com">Florin T.PATRASCU</a>
075: * @since 2.0
076: */
077:
078: public class SAXConfigurationFactory implements ConfigurationFactory {
079: public static final String CONFIG_FILE = "edenlib-config.properties";
080: public static final String DEFAULT_CONFIG_FILE = "/edenlib-default-config.properties";
081:
082: private static final Log log = LogFactory
083: .getLog(SAXConfigurationFactory.class);
084: private static final SAXConfigurationFactory INSTANCE = new SAXConfigurationFactory();
085: public static final String PKG = "com.anthonyeden.lib";
086: public static final int BUFFER_SIZE = 4096;
087: private static String className;
088: private static boolean ns = false;
089: private static boolean fallback = false;
090:
091: private SAXConfigurationFactory() {
092: Properties properties = new Properties();
093: InputStream in;
094: try {
095: in = ClassUtilities.getResourceAsStream(CONFIG_FILE);
096:
097: } catch (Exception e) {
098: log.warn("Could not load " + CONFIG_FILE
099: + " file. Falling back to defaults.");
100: in = getClass().getResourceAsStream(DEFAULT_CONFIG_FILE);//"com.bluecast.xml.Piccolo";
101: }
102:
103: try {
104: properties.load(in);
105: className = properties.getProperty("org.xml.sax.parser");
106: ns = properties.getProperty("namespaces").equalsIgnoreCase(
107: "on");
108:
109: //todo: should I move the entire parser initialization here?
110: try {
111: XMLReader xr = null;
112:
113: if (!fallback) {
114: try {
115: xr = (XMLReader) ClassUtilities.loadClass(
116: className).newInstance();
117: } catch (Exception e) {
118: fallback = true;
119: }
120: }
121:
122: if (fallback) {
123: xr = XMLReaderFactory.createXMLReader();
124: }
125:
126: if (xr != null) {
127: log.info("XML Parser used: "
128: + xr.getClass().getName());
129: }
130:
131: if (xr == null)
132: throw new ConfigurationException(
133: "No XML parsers available in the System???");
134:
135: } catch (SAXException e) {
136: e.printStackTrace();
137: } catch (ConfigurationException e) {
138: e.printStackTrace();
139: }
140:
141: } catch (IOException ioe) {
142: ioe.printStackTrace();
143: } finally {
144: if (in != null)
145: try {
146: in.close();
147: } catch (IOException e) {
148: e.printStackTrace();
149: }
150: }
151: }
152:
153: public static SAXConfigurationFactory getInstance() {
154: return INSTANCE;
155: }
156:
157: /**
158: * Get the root Configuration object from the specified InputStream.
159: *
160: * @param id The id of the configuration (file path, URL, etc)
161: * @param in The InputStream
162: * @return The Configuration object
163: * @throws ConfigurationException
164: */
165:
166: public Configuration getConfigurationX(String id, InputStream in)
167: throws ConfigurationException {
168: try {
169: return getConfiguration(id, new InputStreamReader(in,
170: ConfigurationBase.ENCODING));
171: } catch (UnsupportedEncodingException e) {
172: e.printStackTrace();
173: }
174: return null;
175: }
176:
177: /**
178: * Old method used just to maintain the backward compatibility
179: *
180: * @param id
181: * @param in
182: * @return
183: * @throws ConfigurationException
184: * @deprecated
185: */
186: public Configuration getConfiguration(String id, Reader in)
187: throws ConfigurationException {
188:
189: try {
190: return getConfiguration(id, new ByteArrayInputStream(
191: IOUtilities.copyToString(in).getBytes("UTF-8")));
192: } catch (IOException e) {
193: e.printStackTrace();
194: throw new ConfigurationException(e);
195: }
196: }
197:
198: /**
199: * Get the root Configuration object from the specified InputStream.
200: *
201: * @param id The id of the configuration (file path, URL, etc)
202: * @param in The InputStream
203: * @return The Configuration object
204: * @throws ConfigurationException
205: */
206:
207: public Configuration getConfiguration(String id, InputStream in)
208: throws ConfigurationException {
209: SAXConfigurationHandler handler = new SAXConfigurationHandler(
210: this , id);
211:
212: XMLReader xr = null; //XMLReaderFactory.createXMLReader();
213: try {
214: if (!fallback) {
215: try {
216: xr = (XMLReader) ClassUtilities
217: .loadClass(className).newInstance();
218: } catch (Exception e) {
219: fallback = true;
220: }
221: }
222:
223: if (fallback) {
224: xr = XMLReaderFactory.createXMLReader();
225: }
226:
227: if (xr == null)
228: throw new ConfigurationException(
229: "No XML parsers available in the System???");
230:
231: xr.setErrorHandler(handler);
232: xr.setContentHandler(handler);
233:
234: try {
235: xr.setFeature("http://xml.org/sax/features/namespaces",
236: ns);
237: xr
238: .setFeature(
239: "http://xml.org/sax/features/namespace-prefixes",
240: !ns);
241: } catch (SAXException e) {
242: log.info("Warning: could not set namespace feature to "
243: + ns);
244: try {
245: boolean currentValue;
246: log
247: .info("Current value is "
248: + xr
249: .getFeature("http://xml.org/sax/features/namespaces"));
250: } catch (SAXException x) {
251: log
252: .info("Current value is unknown but probably false.");
253: }
254: }
255:
256: xr.parse(new InputSource(in));
257: return handler.getConfiguration();
258:
259: } catch (SAXException e) {
260: Object[] args = { id, e.getMessage() };
261: throw new ConfigurationException(MessageUtilities
262: .getMessage(getClass(), PKG, "parseSAXError", args));
263: } catch (IOException e) {
264: Object[] args = { id, e.getMessage() };
265: throw new ConfigurationException(MessageUtilities
266: .getMessage(getClass(), PKG, "parseIOError", args));
267: }
268: }
269:
270: }
|