new mir Configuration file parser. not used yet. it works very nicely though,
authormh <mh>
Tue, 23 Oct 2001 20:31:32 +0000 (20:31 +0000)
committermh <mh>
Tue, 23 Oct 2001 20:31:32 +0000 (20:31 +0000)
handles errors in the XML file, etc. I stil need to add in the addRequired XML
Path stuff and the Path matching stuff.

source/mir/misc/ConfigException.java [new file with mode: 0755]
source/mir/misc/Location.java [new file with mode: 0755]
source/mir/xml/XmlConfigurator.java [new file with mode: 0755]

diff --git a/source/mir/misc/ConfigException.java b/source/mir/misc/ConfigException.java
new file mode 100755 (executable)
index 0000000..e8a3b1b
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowlegement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowlegement may appear in the software itself,
+ *    if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package mir.misc;
+
+
+import java.io.*;
+
+/**
+ * Signals an error condition during a build.
+ *
+ * @author James Duncan Davidson
+ */
+public class ConfigException extends RuntimeException {
+
+    /** Exception that might have caused this one. */
+    private Throwable cause;
+
+    /** Location in the build file where the exception occured */
+    private Location location = Location.UNKNOWN_LOCATION;
+
+    /**
+     * Constructs a build exception with no descriptive information.
+     */
+    public ConfigException() {
+        super();
+    }
+
+    /**
+     * Constructs an exception with the given descriptive message.
+     * @param msg Description of or information about the exception.
+     */
+    public ConfigException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs an exception with the given message and exception as
+     * a root cause.
+     * @param msg Description of or information about the exception.
+     * @param cause Throwable that might have cause this one.
+     */
+    public ConfigException(String msg, Throwable cause) {
+        super(msg);
+        this.cause = cause;
+    }
+
+    /**
+     * Constructs an exception with the given message and exception as
+     * a root cause and a location in a file.
+     * @param msg Description of or information about the exception.
+     * @param cause Exception that might have cause this one.
+     * @param location Location in the project file where the error occured.
+     */
+    public ConfigException(String msg, Throwable cause, Location location) {
+        this(msg, cause);
+        this.location = location;
+    }
+
+    /**
+     * Constructs an exception with the given exception as a root cause.
+     * @param cause Exception that might have caused this one.
+     */
+    public ConfigException(Throwable cause) {
+        super(cause.toString());
+        this.cause = cause;
+    }
+
+    /**
+     * Constructs an exception with the given descriptive message and a location
+     * in a file.
+     * @param msg Description of or information about the exception.
+     * @param location Location in the project file where the error occured.
+     */
+    public ConfigException(String msg, Location location) {
+        super(msg);
+        this.location = location;
+    }
+
+    /**
+     * Constructs an exception with the given exception as
+     * a root cause and a location in a file.
+     * @param cause Exception that might have cause this one.
+     * @param location Location in the project file where the error occured.
+     */
+    public ConfigException(Throwable cause, Location location) {
+        this(cause);
+        this.location = location;
+    }
+
+    /**
+     * Returns the nested exception.
+     */
+    public Throwable getException() {
+        return cause;
+    }
+
+    /**
+     * Returns the location of the error and the error message.
+     */
+    public String toString() {
+        return location.toString() + getMessage();
+    }
+
+    /**
+     * Sets the file location where the error occured.
+     */
+    public void setLocation(Location location) {
+        this.location = location;
+    }
+
+    /**
+     * Returns the file location where the error occured.
+     */
+    public Location getLocation() {
+        return location;
+    }
+
+    // Override stack trace methods to show original cause:
+    public void printStackTrace() {
+        printStackTrace(System.err);
+    }
+    
+}
diff --git a/source/mir/misc/Location.java b/source/mir/misc/Location.java
new file mode 100755 (executable)
index 0000000..13954a5
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowlegement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowlegement may appear in the software itself,
+ *    if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package mir.misc;
+
+/**
+ * Stores the file name and line number in a file.
+ */
+public class Location {
+    private String fileName;
+    private int lineNumber;
+    private int columnNumber;
+
+    public static final Location UNKNOWN_LOCATION = new Location();
+
+    /**
+     * Creates an "unknown" location.
+     */
+    private Location() {
+        this(null, 0, 0);
+    }
+
+    /**
+     * Creates a location consisting of a file name but no line number.
+     */
+    public Location(String fileName) {
+        this(fileName, 0, 0);
+    }
+
+    /**
+     * Creates a location consisting of a file name and line number.
+     */
+    public Location(String fileName, int lineNumber, int columnNumber) {
+        this.fileName = fileName;
+        this.lineNumber = lineNumber;
+        this.columnNumber = columnNumber;
+    }
+
+    /**
+     * Returns the file name, line number and a trailing space. An error
+     * message can be appended easily. For unknown locations, returns
+     * an empty string.
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+
+        if (fileName != null) {
+            buf.append(fileName);
+
+            if (lineNumber != 0) {
+                buf.append(":");
+                buf.append(lineNumber);
+            }
+
+            buf.append(": ");
+        }
+
+        return buf.toString();
+    }
+}
diff --git a/source/mir/xml/XmlConfigurator.java b/source/mir/xml/XmlConfigurator.java
new file mode 100755 (executable)
index 0000000..a67a7c4
--- /dev/null
@@ -0,0 +1,385 @@
+package mir.xml;
+
+import java.io.*;
+import java.util.*;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.*;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+
+import mir.misc.ConfigException;
+import mir.misc.Location;
+
+/**
+ * Configures a based on
+ * a XML config file.
+ *
+ * Based and inspired by ant's XmlConfigurator.java
+ * It's a simplified version of the ant parser with
+ * the addition of calling set* methods for defined
+ * classes as well as the inclusion of a method to
+ * add parameters (nested tags) that are required.
+ * (the addRequired method) in the config file.
+ *
+ * @author -mh <heckmann@hbe.ca>
+ * @version 2001.10.21
+ */
+
+public class XmlConfigurator {
+
+    private static SAXParserFactory parserFactory = null;
+
+    private SAXParser saxParser;
+    //private Project project;
+    private File configFile;
+    private File configFileParent;
+    private Locator locator;
+
+    //private SaxContext saxContext;
+
+    /**
+     * Configures the Project with the contents of the specified XML file.
+     */
+    public static void configure(File configFile) throws ConfigException {
+        new XmlConfigurator(configFile).parse();
+    }
+
+    /**
+     * Constructs a new Ant parser for the specified XML file.
+     */
+    private XmlConfigurator(File configFile) {
+        this.configFile = new File(configFile.getAbsolutePath());
+        configFileParent = new File(this.configFile.getParent());
+    }
+
+    /**
+     * Parses the config file.
+     */
+    private void parse() throws ConfigException {
+        FileInputStream inputStream = null;
+        InputSource inputSource = null;
+        
+        try {
+            SAXParserFactory factory = SAXParserFactory.newInstance();
+            saxParser = factory.newSAXParser();
+                
+            String uri = "file:" + configFile.getAbsolutePath().replace('\\', '/');
+            for (int index = uri.indexOf('#'); index != -1; index = uri.indexOf('#')) {
+                uri = uri.substring(0, index) + "%23" + uri.substring(index+1);
+            }
+            
+            inputStream = new FileInputStream(configFile);
+            inputSource = new InputSource(inputStream);
+            inputSource.setSystemId(uri);
+            saxParser.parse(inputSource, new RootHandler());
+        }
+        catch(ParserConfigurationException exc) {
+            throw new ConfigException("Parser has not been configured correctly", exc);
+        }
+        catch(SAXParseException exc) {
+            Location location =
+                new Location(configFile.toString(), exc.getLineNumber(), exc.getColumnNumber());
+
+            Throwable t = exc.getException();
+            if (t instanceof ConfigException) {
+                ConfigException be = (ConfigException) t;
+                if (be.getLocation() == Location.UNKNOWN_LOCATION) {
+                    be.setLocation(location);
+                }
+                throw be;
+            }
+            
+            throw new ConfigException(exc.getMessage(), t, location);
+        }
+        catch(SAXException exc) {
+            Throwable t = exc.getException();
+            if (t instanceof ConfigException) {
+                throw (ConfigException) t;
+            }
+            throw new ConfigException(exc.getMessage(), t);
+        }
+        catch(FileNotFoundException exc) {
+            throw new ConfigException(exc);
+        }
+        catch(IOException exc) {
+            throw new ConfigException("Error reading config file", exc);
+        }
+        finally {
+            if (inputStream != null) {
+                try {
+                    inputStream.close();
+                }
+                catch (IOException ioe) {
+                    // ignore this
+                }
+            }
+        }
+    }
+
+    /**
+     * The common superclass for all sax event handlers in Ant. Basically
+     * throws an exception in each method, so subclasses should override
+     * what they can handle.
+     *
+     * Each type of xml element (task, target, etc) in ant will
+     * have its own subclass of AbstractHandler.
+     *
+     * In the constructor, this class    takes over the handling of sax
+     * events from the parent handler, and returns
+     * control back to the parent in the endElement method.
+     */
+    private class AbstractHandler extends DefaultHandler {
+        protected ContentHandler parentHandler;
+
+        public AbstractHandler(ContentHandler parentHandler) {
+            this.parentHandler = parentHandler;
+
+            // Start handling SAX events
+            try {
+                saxParser.getXMLReader().setContentHandler(this);
+            } catch (SAXException e) {
+                throw new ConfigException("Error getting XMLReader",e);
+            }
+                
+        }
+
+        public void startElement(String uri, String tag, String qName, Attributes attrs) throws SAXParseException {
+            throw new SAXParseException("Unexpected element \"" + tag + "\"", locator);
+        }
+
+        public void characters(char[] buf, int start, int end) throws SAXParseException {
+            String s = new String(buf, start, end).trim();
+
+            if (s.length() > 0) {
+                throw new SAXParseException("Unexpected text \"" + s + "\"", locator);
+            }
+        }
+
+        /**
+         * Called when this element and all elements nested into it have been
+         * handeled.
+         */
+        protected void finished() {}
+
+        public void endElement() throws SAXException {
+
+            finished();
+            // Let parent resume handling SAX events
+            saxParser.getXMLReader().setContentHandler(parentHandler);
+        }
+    }
+
+    /**
+     * Handler for the root element. It's only child must be the "mir" element.
+     */
+    private class RootHandler extends DefaultHandler {
+
+        /**
+         * resolve file: URIs as relative to the build file.
+         */
+        public InputSource resolveEntity(String publicId,
+                                         String systemId) {
+        
+        
+            if (systemId.startsWith("file:")) {
+                String path = systemId.substring(5);
+                int index = path.indexOf("file:");
+                
+                // we only have to handle these for backward compatibility
+                // since they are in the FAQ.
+                while (index != -1) {
+                    path = path.substring(0, index) + path.substring(index + 5);
+                    index = path.indexOf("file:");
+                }
+                
+                String entitySystemId = path;
+                index = path.indexOf("%23");
+                // convert these to #
+                while (index != -1) {
+                    path = path.substring(0, index) + "#" + path.substring(index + 3);
+                    index = path.indexOf("%23");
+                }
+
+                File file = new File(path);
+                if (!file.isAbsolute()) {
+                    file = new File(configFileParent, path);
+                }
+                
+                try {
+                    InputSource inputSource = new InputSource(new FileInputStream(file));
+                    inputSource.setSystemId("file:" + entitySystemId);
+                    return inputSource;
+                } catch (FileNotFoundException fne) {
+                    System.out.println(file.getAbsolutePath()+" could not be found");
+                }
+            }
+            // use default if not file or file not found
+            return null;
+        }
+
+        public void startElement(String uri, String tag, String qName, Attributes attrs) throws SAXParseException {
+            if (tag.equals("mir")) {
+                new MirHandler(this).init(tag, attrs);
+            } else {
+                throw new SAXParseException("Config file is not of expected XML type", locator);
+            }
+        }
+
+        public void setDocumentLocator(Locator locator) {
+            XmlConfigurator.this.locator = locator;
+        }
+    }
+
+    /**
+     * Handler for the top level "project" element.
+     */
+    private class MirHandler extends AbstractHandler {
+        public MirHandler(ContentHandler parentHandler) {
+            super(parentHandler);
+        }
+
+        public void init(String tag, Attributes attrs) throws SAXParseException {
+            String name = null;
+
+            for (int i = 0; i < attrs.getLength(); i++) {
+                String key = attrs.getLocalName(i);
+                String value = attrs.getValue(i);
+
+                if (key.equals("name")) {
+                    name = value;
+                } else {
+                    throw new SAXParseException("Unexpected attribute \"" + attrs.getLocalName(i) + "\"", locator);
+                }
+            }
+
+            if (name == null) {
+                throw new SAXParseException("The default attribute of \"name\" is required", 
+                                            locator);
+            }
+            
+            //MirConfig.setName(name);
+
+        }
+
+        public void startElement(String uri, String name, String qName, Attributes attrs) throws SAXParseException {
+            if (name.equals("class")) {
+                handleClassdef(name, attrs);
+            } else {
+                throw new SAXParseException("Unexpected element \"" + name + "\"", locator);
+            }
+        }
+
+        private void handleClassdef(String name, Attributes attrs) throws SAXParseException {
+            (new ClassHandler(this)).init(name, attrs);
+        }
+
+    }
+
+    /**
+     * Handler for "class" elements.
+     */
+    private class ClassHandler extends AbstractHandler {
+
+        Class classN;
+
+        public ClassHandler(ContentHandler parentHandler) {
+            super(parentHandler);
+        }
+
+        public void init(String tag, Attributes attrs) throws SAXParseException {
+            String name = null;
+
+            for (int i = 0; i < attrs.getLength(); i++) {
+                String key = attrs.getLocalName(i);
+                String value = attrs.getValue(i);
+
+                if (key.equals("name")) {
+                    name = value;
+                } else {
+                    throw new SAXParseException("Unexpected attribute \"" + key + "\"", locator);
+                }
+            }
+
+            if (name == null) {
+                throw new SAXParseException("class element appears without a \"name\" attribute", locator);
+            }
+
+            try {
+                classN=Class.forName(name);
+            } catch (ClassNotFoundException e) {
+                throw new ConfigException("Error invoking class: \""+name+
+                    "\"",e);
+            }
+
+        }
+
+        public void startElement(String uri, String name, String qName, Attributes attrs) throws SAXParseException {
+            if (name.equals("property")) {
+                handleProperties(name, attrs);
+            } else {
+                throw new SAXParseException("Unexpected element \"" + name + "\"", locator);
+            }
+        }
+
+        private void handleProperties(String name, Attributes attrs) throws SAXParseException {
+            (new PropertiesHandler(this, classN )).init(name, attrs);
+        }
+
+    }
+
+    /**
+     * Handler for all property elements.
+     */
+    private class PropertiesHandler extends AbstractHandler {
+        private Class classN;
+
+        public PropertiesHandler(ContentHandler parentHandler, Class classN) {
+            super(parentHandler);
+
+            this.classN = classN;
+        }
+
+        public void init(String tag, Attributes attrs) throws SAXParseException {
+            String name=null;
+            String value=null;
+
+            for (int i = 0; i < attrs.getLength(); i++) {
+                String key = attrs.getLocalName(i);
+                String v = attrs.getValue(i);
+
+                if (key.equals("name")) {
+                    name = v;
+                } else if (key.equals("value")) {
+                    value = v; 
+                } else {
+                    throw new SAXParseException("Unexpected attribute \"" + key + "\"", locator);
+                }
+            }
+
+            if (name == null) {
+                throw new SAXParseException("property element appears without a \"name\" attribute", locator);
+            }
+            if (value == null) {
+                throw new SAXParseException("property element appears without a \"value\" attribute", locator);
+            }
+            /////
+        }
+
+        protected void finished() {
+          //do the setting here?
+        }
+
+    }
+
+    private static String capitalize(String name) {
+        if (name == null || name.length() == 0) {
+            return name;
+        }
+        char chars[] = name.toCharArray();
+        chars[0] = Character.toUpperCase(chars[0]);
+        return new String(chars);
+    }
+
+}