--- /dev/null
+/*
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+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);
+ }
+
+}