Java tutorial
/* * Copyright (C) 2009 Istvan Fehervari, Wilfried Elmenreich * Original project page: http://www.frevotool.tk * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License Version 3 as published * by the Free Software Foundation http://www.gnu.org/licenses/gpl-3.0.txt * * There is no warranty for this free software. The GPL requires that * modified versions be marked as changed, so that their problems will * not be attributed erroneously to authors of previous versions. */ package core; import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.Scanner; import main.FrevoMain; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.Node; import utils.NESRandom; import utils.SafeSAX; /** * Class loading and keeping all data about a single component read from an XML * descriptor file. Use this class to load all data about a component before * instantiating it. * * @author Istvan Fehervari */ public class ComponentXMLData { /** Holds the root class of this component. */ protected Class<? extends AbstractComponent> componentClass; /** Refers to the name of the root class. */ private String className; /** Path pointing to the directory of the root class. */ private String classDir; /** A short description of this component. */ private String description; /** Path pointing to the location of the reference image of this component. */ private String imageLocation = null; /** Refers to the name of this component. */ private String name; /** Refers to the author of this component. */ private String author; /** Refers to the version of this component. */ private String version; /** * Holds a reference to the root XML file that was used to construct this * object. */ private File sourceXMLFile; /** A list of keywords describing this component. */ private ArrayList<String> keywords = new ArrayList<String>(); /** * Indicates if constructing this class (loading all data from XML) happened * successfully. Only used in the constructor. */ private boolean loadedSuccessfully; /** Refers to the type of this component. E.g. problem, method, etc. */ protected ComponentType componentType; /** A map containing the property entries of this component. */ protected Hashtable<String, XMLFieldEntry> properties = new Hashtable<String, XMLFieldEntry>(); /** * Constructor of this class. Basically, it loads up all the data from the * given XML file and puts them in the appropriate variables. * * @param ctype * The type of this component. * @param xmlfile * The XML file used to load up data into this class. */ public ComponentXMLData(ComponentType ctype, File xmlfile) { // monitor if loading encounters errors or not loadedSuccessfully = true; // set the type of this component this.componentType = ctype; // sets the source of this class setSourceXMLFile(xmlfile); // load the XML file Document doc = SafeSAX.read(xmlfile, true); try { // Load configuration section Node nd = doc.selectSingleNode("/icomponent/config"); if (nd == null) { System.out.println("No config tag found - Excluding component at "); // configuration tag is required loadedSuccessfully = false; } else { List<?> npops = nd.selectNodes(".//entry"); Iterator<?> it = npops.iterator(); while (it.hasNext()) { Element el = (Element) it.next(); String key = el.valueOf("./@key"); String value = el.valueOf("./@value"); if (key.equals("classdir")) { // get root class directory setClassDir(value); } else if (key.equals("classname")) { // get root class name setClassName(value); } else if (key.equals("name")) { // get component name setName(value); } else if (key.equals("description")) { // get description setDescription(value); } else if (key.equals("author")) { // get author setAuthor(value); } else if (key.equals("version")) { // get version setVersion(value); } else if (key.equals("image")) { // get reference image path setImageLocation(value); } else if (key.equals("tags")) { // read all tags ArrayList<String> keywordlist = new ArrayList<String>(); Scanner sc = new Scanner(value); sc.useDelimiter(","); while (sc.hasNext()) keywordlist.add(sc.next()); setKeywords(keywordlist); sc.close(); } else if (key.equals("isBulkRepresentation")) { if (Boolean.parseBoolean(value)) { this.componentType = ComponentType.FREVO_BULKREPRESENTATION; } } } // Load class file String classdir = getClassDir(); String dir = FrevoMain.getInstallDirectory() + File.separator + "Components" + File.separator + FrevoMain.getComponentTypeAsString(ctype) + "s" + File.separator + classdir + File.separator; try { // Create a new class loader with the directory ComponentClassLoader cl = new ComponentClassLoader(dir); // Load in the class Class<?> loadedclass = cl.loadClass(getClassName(), true); setComponentClass(loadedclass.asSubclass(AbstractComponent.class)); } catch (ClassNotFoundException e) { System.err.println("Class not found: " + getClassName()); // root class is required loadedSuccessfully = false; } catch (Exception e) { // for anything else System.err.println("Class unavailable to load: " + getName()); loadedSuccessfully = false; } } // Load properties section Node nd2 = doc.selectSingleNode("/icomponent/properties"); if (nd2 == null) { System.out.println("No properties tag found for component " + getName()); } else { List<?> npops = nd2.selectNodes(".//propentry"); Iterator<?> it = npops.iterator(); // create hashmap for the properties Hashtable<String, XMLFieldEntry> proptable = new Hashtable<String, XMLFieldEntry>(); while (it.hasNext()) { Element el = (Element) it.next(); String key = el.valueOf("./@key"); XMLFieldType type = XMLFieldType.valueOf(el.valueOf("./@type")); String value = el.valueOf("./@value"); String description = el.valueOf("./@description"); if (!FrevoMain.checkType(type, value)) throw new IllegalArgumentException( "Value \"" + value + "\" for Key \"" + key + "\" is not of type " + type + "!"); if (type.equals(XMLFieldType.ENUM)) { String enumName = el.valueOf("./@enumName"); proptable.put(key, new XMLFieldEntry(value, type, enumName, description)); } else { proptable.put(key, new XMLFieldEntry(value, type, description)); } } // Add hashmap to the object setProperties(proptable); } } catch (OutOfMemoryError mem) { System.err.println("Could not import! (Out of memory)"); loadedSuccessfully = false; } catch (IllegalArgumentException e) { System.out.println("IllegalArgumentException\n" + e.getMessage()); loadedSuccessfully = false; } } /** * Indicates if the loading process encountered no errors. If true there * might be required data missing, therefore using this class is not * advised. * * @return True if component is loaded successfully and ready to be used. */ public boolean isLoadedSuccessfully() { return loadedSuccessfully; } /** * Returns a map containing the loaded property pairs defined in the XML * file. * * @return A map holding all properties of this component. */ public Hashtable<String, XMLFieldEntry> getProperties() { return properties; } /** * Returns the type of this component. * * @return The type of this component. */ public ComponentType getComponentType() { return this.componentType; } /** * Sets the properties map to the given value. * * @param properties * The new properties map to be used. */ private void setProperties(Hashtable<String, XMLFieldEntry> properties) { this.properties = properties; } /** * Returns the root class of this component. * * @return The root class of this component. */ public Class<? extends AbstractComponent> getComponentClass() { return componentClass; } /** * Sets the root class of this component to the given class. * * @param componentclass * The new root class to be used. */ private void setComponentClass(Class<? extends AbstractComponent> componentclass) { this.componentClass = componentclass; } /** * Returns the root class name of this component as it is defined in the XML * file. Typically, it includes the whole name of the class with the package * definition included. * * @return The name of the root class. */ public String getClassName() { return className; } /** * Sets the root class name to the given value. * * @param The * new class name to be used. */ private void setClassName(String classname) { this.className = classname; } /** * Returns the path of base directory of the root class as it is defined in * the XML file. * * @return The base directory of the root class. */ public String getClassDir() { return classDir; } /** * Sets the path to the base directory to the given value. * * @param classdir * The new path to the base directory to be used. */ private void setClassDir(String classdir) { this.classDir = classdir; } /** * Returns the description of this problem as it is defined in the XML file. * * @return A short description of this component. */ public String getDescription() { return description; } /** * Sets the description of this component to a new <code>String</code> * value. * * @param description * The new description to be used. */ private void setDescription(String description) { this.description = description; } /** * Returns the author value defined in the source XML file. * * @return The author of this component. */ public String getAuthor() { return author; } /** * Sets the author of this component to a new <code>String</code> value. * * @param author * The new author to be set. */ private void setAuthor(String author) { this.author = author; } /** * Returns the version of this problem as it is defined in the XML file. * * @return The version of this component as a <tt>String</tt> object. */ public String getVersion() { return version; } /** * Sets the version of this component to a new <code>String</code> value. * * @param version * The new version to be set. */ private void setVersion(String version) { this.version = version; } /** * Returns the path to the reference image of this component as it is * defined in the XML file. * * @return The path to the reference image. */ public String getImageLocation() { return imageLocation; } /** * Sets the path to the reference image of this component to the given * value. * * @param imagelocation * The new location of the reference image. */ private void setImageLocation(String imagelocation) { this.imageLocation = imagelocation; } /** * Returns a human-readable name of this component as it is defined in the * XML file. * * @return The name of this component. */ public String getName() { return name; } /** * Sets the name if this component to the given value. * * @param name * The name to be used. */ private void setName(String name) { this.name = name; } /** * Sets the reference of the source XML file to the given value. * * @param sourcexml * The new reference to be used. */ private void setSourceXMLFile(File sourcexml) { this.sourceXMLFile = sourcexml; } /** * Returns a reference to the source XML file used to construct this * component. * * @return A reference to the source XML file. */ public File getSourceXMLFile() { return this.sourceXMLFile; } /** * Returns a new <i>method</i> instance created from this source data. * Throws <code>InstantiationException</code> if this component is not a * method description. * * @return A new <i>method</i> instance * @throws InstantiationException * if this component is not a method descriptor */ public AbstractMethod getNewMethodInstance(NESRandom random) throws InstantiationException { // check component type if (getComponentType() != ComponentType.FREVO_METHOD) { throw new InstantiationException(); } // return a new instance Constructor<?>[] c = getComponentClass().getConstructors(); AbstractMethod result; try { result = (AbstractMethod) c[0].newInstance(random); result.setProperties(properties); result.setXMLData(this); return result; } catch (Exception e) { throw new InstantiationException(); } } /** * Returns a new <i>representation</i> instance created from this source * data. Throws <code>InstantiationException</code> if this component is not * a representation description. * * @return A new <i>representation</i> instance * @throws InstantiationException * if this component is not a representation descriptor */ public AbstractRepresentation getNewRepresentationInstance(int inputnumber, int outputnumber, NESRandom random) throws IllegalAccessException, InvocationTargetException, InstantiationException { // check component type if ((getComponentType() != ComponentType.FREVO_REPRESENTATION) && (getComponentType() != ComponentType.FREVO_BULKREPRESENTATION)) { throw new InstantiationException(); } // try to run static initializer try { Method initializer = getComponentClass().getDeclaredMethod("initialize", Integer.TYPE, Integer.TYPE, Hashtable.class, Random.class); initializer.setAccessible(true); initializer.invoke(null, inputnumber, outputnumber, properties, random); } catch (SecurityException e1) { System.err.println("Warning: Cannot run static initializer for class " + getClassName()); } catch (NoSuchMethodException e1) { // ignore } // return a new instance Constructor<?>[] c = getComponentClass().getConstructors(); AbstractRepresentation result; try { result = null; if (getComponentType() == ComponentType.FREVO_REPRESENTATION) { for (Constructor<?> constructor : c) { try { result = (AbstractRepresentation) constructor.newInstance(inputnumber, outputnumber, random, getProperties()); break; } catch (Exception ex) { // nothing to do here because we have to check out all // constructors } } } else { for (Constructor<?> constructor : c) { try { result = (AbstractBulkRepresentation) constructor.newInstance(inputnumber, outputnumber, random, getProperties()); break; } catch (Exception ex) { // nothing to do here because we have to check out all // constructors } } } if (result == null) { throw new IllegalArgumentException("There is no suitable constructor to create representation"); } result.setProperties(properties); result.setXMLData(this); return result; } catch (IllegalArgumentException e) { throw e; } } /** * Returns a new <i>ranking</i> instance created from this source data. * Throws <code>InstantiationException</code> if this component is not a * ranking description. * * @return A new <i>ranking</i> instance * @throws InstantiationException * if this component is not a ranking descriptor */ public AbstractRanking getNewRankingInstance() throws InstantiationException { // check component type if (getComponentType() != ComponentType.FREVO_RANKING) { throw new InstantiationException(); } // return a new instance Constructor<?> c; AbstractRanking result; try { c = getComponentClass().getDeclaredConstructor(Hashtable.class); result = (AbstractRanking) c.newInstance(properties); result.setXMLData(this); } catch (Exception itx) { throw new InstantiationException(itx.getMessage()); } return result; } /** * Returns the type of the given property key. * * @param key * The property key whose type is requested. * @return A reference to the property type stored within this component. */ public XMLFieldType getTypeOfProperty(String key) { XMLFieldEntry entr = this.properties.get(key); if (entr == null) throw new IllegalArgumentException("Key " + key + " not found!"); return entr.getType(); } /** * Returns the value assigned to the given property key. * * @param key * The property key whose assigned value is requested. * @return A reference to the <code>String</code> value assigned to the * given property key. */ public String getValueOfProperty(String key) { XMLFieldEntry entr = this.properties.get(key); if (entr == null) throw new IllegalArgumentException("Key " + key + " not found!"); return entr.getValue(); } /** * Returns a reference to a list containing the keywords as defined in the * source XML file. * * @return A list of keywords. */ public ArrayList<String> getKeywords() { return keywords; } /** * Sets the list of keywords to the given reference. * * @param keywords * The new list of keywords to be used. */ private void setKeywords(ArrayList<String> keywords) { this.keywords = keywords; } /** * Returns a <code>String</code> representation of this component. * * @return A <code>String</code> representation of this component. */ public String toString() { return getName(); } }