// Copyright 2012 Georg-August-Universität Göttingen, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package de.ugoe.cs.autoquest.eventcore.guimodel; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Properties; import java.util.logging.Level; import de.ugoe.cs.util.console.Console; /** *

* Creates {@link IGUIElement}s from a given specification. Implemented as singleton. *

* * @version 1.0 * @author Patrick Harms */ public class GUIElementFactory implements IGUIElementFactory { /** *

* Instance of the class (singleton) *

*/ private static GUIElementFactory instance = new GUIElementFactory(); /** *

* Constructor. Creates a new GUIElementFactory. Private to preserve singleton property. *

*/ private GUIElementFactory() {} /** *

* Returns the instance of this class. *

* * @return the instance */ public static synchronized GUIElementFactory getInstance() { return instance; } /** *

* A property mapping that defines to which Java class is created given the type of the GUI * element found in the specification. *

*/ private Properties mappingsFromConfiguration; /* * (non-Javadoc) * * @see * de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementFactory#instantiateGUIElement(de.ugoe.cs.autoquest * .eventcore.guimodel.IGUIElementSpec, de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement) */ @Override public IGUIElement instantiateGUIElement(IGUIElementSpec specification, IGUIElement parent) throws GUIModelConfigurationException { Properties mappings = getMappingsFromConfiguration(); IGUIElement guiElement = null; String[] typeHierarchy = specification.getTypeHierarchy(); int i = 0; String className = null; while ((className == null) && (i < typeHierarchy.length)) { className = mappings.getProperty(typeHierarchy[i]); i++; } if (className != null) { try { Class clazz = this.getClass().getClassLoader().loadClass(className); if (!IGUIElement.class.isAssignableFrom(clazz)) { Console.traceln(Level.WARNING, "configured GUI element representing class " + className + " is no valid GUIElement derivate."); return null; } Constructor constructor = null; Class parentClass = (parent == null) ? null : parent.getClass(); // search for a constructor, that perfectly matches the types for (Constructor candidate : clazz.getConstructors()) { if ((parentClass != null) && (candidate.getParameterTypes().length == 2) && (candidate.getParameterTypes()[0].equals(specification.getClass())) && (candidate.getParameterTypes()[1].equals(parentClass))) { constructor = candidate; break; } else if (parentClass == null) { if ((candidate.getParameterTypes().length >= 1) && (candidate.getParameterTypes()[0].equals(specification.getClass()))) { constructor = candidate; break; } } } if (constructor == null) { // search for an assignable constructor for (Constructor candidate : clazz.getConstructors()) { if ((candidate.getParameterTypes().length == 2) && (candidate.getParameterTypes()[0].isInstance(specification)) && (candidate.getParameterTypes()[1].isInstance(parent))) { constructor = candidate; break; } } } if (constructor != null) { guiElement = (IGUIElement) constructor.newInstance(specification, parent); } else { throw new NoSuchMethodException ("no constructor with two parameters and assignable parameter types for " + specification.getClass() + " and " + (parent != null ? parent.getClass() : "null") + " found in class " + clazz); } } catch (ClassNotFoundException e) { Console.traceln(Level.WARNING, "configured GUI element representing class " + className + " can not be loaded."); throw new GUIModelConfigurationException ("configured GUI element representing class " + className + " can not be loaded.", e); } catch (SecurityException e) { Console.traceln(Level.WARNING, "configured GUI element representing class " + className + " can not be instantiated due to security reasons."); throw new GUIModelConfigurationException ("configured GUI element representing class " + className + " can not be instantiated due to security reasons.", e); } catch (NoSuchMethodException e) { Console.traceln(Level.WARNING, "configured GUI element representing class " + className + " does not provide an appropriate constructor."); throw new GUIModelConfigurationException ("configured GUI element representing class " + className + " does not provide an appropriate constructor.", e); } catch (IllegalArgumentException e) { Console.traceln(Level.WARNING, "configured GUI element representing class " + className + " does not provide an appropriate constructor " + "accepting the provided parameters."); throw new GUIModelConfigurationException ("configured GUI element representing class " + className + " does not " + "provide an appropriate constructor accepting the provided parameters.", e); } catch (InstantiationException e) { Console.traceln(Level.WARNING, "configured GUI element representing class " + className + " can not be instantiated."); throw new GUIModelConfigurationException ("configured GUI element representing class " + className + " can not be instantiated.", e); } catch (IllegalAccessException e) { Console.traceln(Level.WARNING, "configured GUI element representing class " + className + " can not be instantiated."); throw new GUIModelConfigurationException ("configured GUI element representing class " + className + " can not be instantiated.", e); } catch (InvocationTargetException e) { Console.traceln(Level.WARNING, "configured GUI element representing class " + className + " can not be instantiated."); throw new GUIModelConfigurationException ("configured GUI element representing class " + className + " can not be instantiated.", e); } } if (guiElement == null ) { Console.traceln(Level.WARNING, "no class representing GUI elements of type " + specification.getType() + " found. Please extend GUI element " + "mapping files."); throw new GUIModelConfigurationException ("no class representing GUI elements of type " + specification.getType() + " found. Please extend GUI element mapping files"); } return guiElement; } /** *

* Loads the mappings for GUI elements. All files that start with "guimapping", end * with ".txt", and are located in the folder "data/guimappings" (relative * to the working directory) are loaded. *

* * @return loaded GUI mappings */ private synchronized Properties getMappingsFromConfiguration() throws GUIModelConfigurationException { if (mappingsFromConfiguration != null) { return mappingsFromConfiguration; } else { mappingsFromConfiguration = new Properties(); File mappingsFolder = new File("data/guimappings"); File[] children = mappingsFolder.listFiles(); if (children != null) { for (File mappingsFile : children) { if (!mappingsFile.isDirectory() && mappingsFile.getName().startsWith("guimapping") && mappingsFile.getName().endsWith(".txt")) { InputStream inStream = null; try { inStream = new FileInputStream(mappingsFile); mappingsFromConfiguration.load(inStream); } catch (FileNotFoundException e) { throw new GUIModelConfigurationException( "could not read mapping configuration file " + mappingsFile, e); } catch (IOException e) { throw new GUIModelConfigurationException( "could not read mapping configuration file " + mappingsFile, e); } finally { if (inStream != null) { try { inStream.close(); } catch (IOException e) { // ignore } } } } } } else { throw new GUIModelConfigurationException( "no GUI mappings file provided in folder " + mappingsFolder); } return mappingsFromConfiguration; } } }