Customization.java :  » Testing » jacareto » jacareto » system » Java Open Source

Java Open Source » Testing » jacareto 
jacareto » jacareto » system » Customization.java
/*
 * Jacareto Copyright (c) 2002-2005
 * Applied Computer Science Research Group, Darmstadt University of
 * Technology, Institute of Mathematics & Computer Science,
 * Ludwigsburg University of Education, and Computer Based
 * Learning Research Group, Aachen University. All rights reserved.
 *
 * Jacareto is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * Jacareto is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with Jacareto; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

package jacareto.system;


import jacareto.toolkit.EnhancedHashtable;
import jacareto.toolkit.io.FileUtilities;

import org.apache.regexp.RE;
import org.apache.regexp.RESyntaxException;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Properties;
import java.util.StringTokenizer;

/**
 * Enhanced hashtable which can read the customization out of a xml file and stores it in a
 * hashtable. The xml file must have the following form:
 * <pre>
 *  &lt;customization&gt;
 *  &lt;elem name="MyElement0" value="Value0"/&gt;
 *  &lt;group name="MyGroup1"&gt;
 *  &lt;elem name="MyElement1" value="Value1"/&gt;
 *  &lt;elem name="MyElement2" value="Value2"/&gt;
 *  &lt;/group&gt;
 *  &lt;group name="MyGroup2"&gt;
 *  &lt;group name="MyGroup3"&gt;
 *  &lt;elem name="MyElement3" value="Value3"/&gt;
 *  &lt;elem name="MyElement4" value="Value4"/&gt;
 *  &lt;/group&gt;
 *  &lt;elem name="MyElement5" value="Value5"/&gt;
 *  &lt;/group&gt;
 *  &lt;/customization&gt;
 *  </pre>
 * This example code will add the following (key,value) pairs to the customization (as strings):
 * <pre>
 *  ("MyElement0", "Value0")
 *  ("MyGroup1.MyElement1", "Value1")
 *  ("MyGroup1.MyElement2", "Value2")
 *  ("MyGroup2.MyGroup3.MyElement3", "Value3")
 *  ("MyGroup2.MyGroup3.MyElement4", "Value4")
 *  ("MyGroup2.MyElement5", "Value5")
 *  </pre>
 * Another valid xml element is a map. A map consists of (key,value) pairs. If the xml file
 * contains a map, then an instance of type {@link jacareto.toolkit.EnhancedHashtable} will be
 * added to the customization containing the specified (key,value) pairs. Example xml file:
 * <pre>
 *  &lt;customization&gt;
 *  &lt;group name="MyGroup1"&gt;
 *  &lt;elem name="MyElement1" value="Value1"/&gt;
 *  &lt;map name="Map1"&gt;
 *  &lt;mapelem key="k1" value="v1"/&gt;
 *  &lt;mapelem key="k2" value="v2"/&gt;
 *  &lt;mapelem key="k3" value="v3"/&gt;
 *  &lt;/map&gt;
 *  &lt;/group&gt;
 *  &lt;/customization&gt;
 *  </pre>
 * 
 * <p>
 * This xml file will produce two customization elements: a normal element ("MyGroup1.MyElement1",
 * "Value1") and a hashtable containing the three (key,value) pairs (k1,v1), (k2,v2) and (k3,v3).
 * The hashtable will be added to the customization belonging to the key "MyGroup1.Map1".
 * </p>
 * 
 * <p>
 * No text of a "name" attribute may contain a ".", because this character is used to keep the
 * hierarchy. For "key" attributes of map elements it is allowed to contain dots.
 * </p>
 *
 * @author <a href="mailto:cspannagel@web.de">Christian Spannagel</a>
 * @version 1.02
 */
public class Customization extends EnhancedHashtable {
    /** The attributes of the root element. */
    private Hashtable rootAttributes;

    /**
     * Creates an empty customization object.
     */
    public Customization () {
        super();
        rootAttributes = new Hashtable();
    }

    /**
     * Creates a customization object and reads the data out of the specified filename.
     *
     * @param filename the filename of the xml file
     *
     * @throws IOException if the given file cannot be parsed
     */
    public Customization (String filename) throws IOException {
        this();
        read (filename);
    }

    /**
     * Creates a customization object and and reads all elements from the given properties
     * instance.
     *
     * @param properties the properties
     */
    public Customization (Properties properties) {
        this();
        putAll (properties);
    }

    /**
     * Creates a customization object and reads the data from the specified input stream.
     *
     * @param inputStream the input stream
     *
     * @throws IOException if the given input stream cannot be parsed
     */
    public Customization (InputStream inputStream) throws IOException {
        this();
        read (inputStream);
    }

    /**
     * Reads the customization from a xml file or a properties file and stores it to the hashtable.
     * The hashtable will not be cleared before (if you want to add the xml file customization to
     * an empty hashtable, clear the hashtable first).
     *
     * @param filename the filename of the xml file
     *
     * @throws IOException if the given file cannot be parsed
     */
    public void read (String filename) throws IOException {
        try {
            if (FileUtilities.getExtension (filename).equals ("xml")) {
                RE re = new RE("(/|\\\\)");
                filename = re.subst (filename, File.separator);

                SAXBuilder builder = new SAXBuilder();
                Document xmlEventRecordDocument = builder.build (new File(filename));
                Element rootElement = xmlEventRecordDocument.getRootElement ();
                addXMLTree (rootElement, "");
            } else {
                Properties properties = new Properties();
                properties.load (new FileInputStream(filename));
                putAll (properties);
            }
        } catch (JDOMException ex) {
            throw new IOException("Customization: Could not parse the file " + filename + ".\n" +
                ex.getMessage ());
        } catch (IOException ex) {
            throw new IOException("Customization: Could not parse the file " + filename + ".\n" +
                ex.getMessage ());
        } catch (RESyntaxException ignored) {
            ;
        }
    }

    /**
     * Reads the customization from an input stream and stores it to the hashtable. The hashtable
     * will not be cleared before (if you want to add the xml file customization to an empty
     * hashtable, clear the hashtable first).
     *
     * @param inputStream the filename of the xml file
     *
     * @throws IOException if the given input stream cannot be parsed
     */
    public void read (InputStream inputStream) throws IOException {
        try {
            SAXBuilder builder = new SAXBuilder();
            Document xmlEventRecordDocument = builder.build (inputStream);
            Element rootElement = xmlEventRecordDocument.getRootElement ();
            addXMLTree (rootElement, "");
        } catch (JDOMException ex) {
            throw new IOException("Customization: Could not parse a given input stream.");
        }
    }

    /**
     * Writes the customization to a xml file with the given filename.
     *
     * @param filename the filename of the target file
     *
     * @throws IOException if the customization cannot be written
     */
    public void write (String filename) throws IOException {
        write (filename, "customization");
    }

    /**
     * Adds a (key, value) pair to the XML tree given by the root element.
     *
     * @param root the root element
     * @param key the key
     * @param value the value belonging to the key
     */
    protected void writeXMLElement (Element root, String key, Object value) {
        Element element = root;
        StringTokenizer st = new StringTokenizer(key, ".", false);

        while (st.hasMoreTokens ()) {
            String elemName = st.nextToken ();
            Element child = null;

            if (st.hasMoreTokens ()) {
                Iterator it = element.getChildren ().iterator ();

                while ((child == null) && it.hasNext ()) {
                    Element groupChild = (Element) it.next ();

                    if (groupChild.getName ().equals ("group") &&
                            groupChild.getAttributeValue ("name", "").equals (elemName)) {
                        child = groupChild;
                    }
                }

                if (child == null) {
                    child = new Element("group");
                    child.setAttribute ("name", elemName);
                    element.addContent (child);
                }

                element = child;
            } else {
                if (! (value instanceof EnhancedHashtable)) {
                    child = new Element("elem");
                    child.setAttribute ("name", elemName);
                    child.setAttribute ("value", value.toString ());
                } else {
                    child = new Element("map");
                    child.setAttribute ("name", elemName);

                    EnhancedHashtable valueTable = (EnhancedHashtable) value;
                    Enumeration enumeration = valueTable.keys ();

                    while (enumeration.hasMoreElements ()) {
                        Object valueKey = enumeration.nextElement ();
                        Element mapChild = new Element("mapelem");
                        mapChild.setAttribute ("key", valueKey.toString ());
                        mapChild.setAttribute ("value", valueTable.get (valueKey).toString ());
                        child.addContent (mapChild);
                    }
                }

                element.addContent (child);
            }
        }
    }

    /**
     * Adds the tree whose root is the specified element to the hashtable. The name of the element
     * must be contained in the set {customization, group}.
     *
     * @param root the root element
     * @param prefix the prefix for all keys read out of the file
     */
    private void addXMLTree (Element root, String prefix) {
        String rootName = root.getName ();

        if (rootName.equals ("customization") || rootName.equals ("group") ||
                rootName.equals ("module")) {
            if (rootName.equals ("module")) {
                rootAttributes.put ("name", root.getAttributeValue ("name"));
                rootAttributes.put ("author", root.getAttributeValue ("author"));
                rootAttributes.put ("version", root.getAttributeValue ("version"));
            }

            Iterator i = root.getChildren ().iterator ();

            while (i.hasNext ()) {
                Element element = (Element) i.next ();
                Attribute nameAttribute = element.getAttribute ("name");

                if (nameAttribute == null) {
                    System.err.println ("XMLFile error: name missing!");
                    System.exit (1);
                }

                String elementName = prefix + (prefix.equals ("") ? "" : ".") +
                    nameAttribute.getValue ();

                if (element.getName ().equals ("group")) {
                    addXMLTree (element, elementName);
                } else if (element.getName ().equals ("map")) {
                    EnhancedHashtable map = new EnhancedHashtable();

                    if (containsKey (elementName)) {
                        Object alreadyContained = get (elementName);

                        if (alreadyContained instanceof EnhancedHashtable) {
                            map = (EnhancedHashtable) alreadyContained;
                        }
                    }

                    Iterator itMap = element.getChildren ().iterator ();

                    while (itMap.hasNext ()) {
                        Element mapElement = (Element) itMap.next ();

                        if (mapElement.getName ().equals ("mapelem")) {
                            Attribute keyAttribute = mapElement.getAttribute ("key");
                            Attribute valueAttribute = mapElement.getAttribute ("value");

                            if ((keyAttribute == null) || (valueAttribute == null)) {
                                System.err.println ("XMLFile Error (Map): key or value missing!");
                                System.exit (1);
                            }

                            map.put (keyAttribute.getValue (), valueAttribute.getValue ());
                        }
                    }

                    put (elementName, map);
                } else if (element.getName ().equals ("elem")) {
                    Attribute valueAttribute = element.getAttribute ("value");

                    if (valueAttribute == null) {
                        System.err.println ("XMLFile Error: value missing!");
                        System.exit (1);
                    }

                    put (elementName, valueAttribute.getValue ());
                }
            }
        }
    }

    /**
     * Returns the attributes of the customization. If the customization is read from a xml file,
     * those attributes are the attributes of the root element.
     *
     * @return DOCUMENT ME!
     */
    public Hashtable getAttributes () {
        return rootAttributes;
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.