source: trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIElementFactory.java @ 2252

Last change on this file since 2252 was 2146, checked in by pharms, 7 years ago
  • refactored GUI model so that hierarchical event target structures can also be used and created by plugins not being strictly for GUIs
File size: 13.7 KB
RevLine 
[927]1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
[831]14
[922]15package de.ugoe.cs.autoquest.eventcore.guimodel;
[545]16
[585]17import java.io.File;
18import java.io.FileInputStream;
19import java.io.FileNotFoundException;
[545]20import java.io.IOException;
21import java.io.InputStream;
[604]22import java.lang.reflect.Constructor;
[545]23import java.lang.reflect.InvocationTargetException;
24import java.util.Properties;
25import java.util.logging.Level;
26
[2146]27import de.ugoe.cs.autoquest.eventcore.EventTargetModelConfigurationException;
28import de.ugoe.cs.autoquest.eventcore.HierarchicalEventTargetModel;
29import de.ugoe.cs.autoquest.eventcore.IEventTargetFactory;
30import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
31import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget;
[724]32import de.ugoe.cs.util.console.Console;
33
[545]34/**
[831]35 * <p>
36 * Creates {@link IGUIElement}s from a given specification. Implemented as singleton.
37 * </p>
[545]38 *
[831]39 * @version 1.0
40 * @author Patrick Harms
[545]41 */
[2146]42public class GUIElementFactory implements IEventTargetFactory {
[831]43
44    /**
45     * <p>
46     * Instance of the class (singleton)
47     * </p>
48     */
[592]49    private static GUIElementFactory instance = new GUIElementFactory();
[585]50
51    /**
[831]52     * <p>
53     * Constructor. Creates a new GUIElementFactory. Private to preserve singleton property.
54     * </p>
[585]55     */
[831]56    private GUIElementFactory() {}
[585]57
58    /**
[831]59     * <p>
60     * Returns the instance of this class.
61     * </p>
[585]62     *
[831]63     * @return the instance
[585]64     */
[592]65    public static synchronized GUIElementFactory getInstance() {
[585]66        return instance;
67    }
68
[545]69    /**
[831]70     * <p>
[2146]71     * A property mapping that defines which Java class is created given the type of the GUI
[831]72     * element found in the specification.
73     * </p>
[545]74     */
[831]75    private Properties mappingsFromConfiguration;
[545]76
[831]77   
[2146]78    /* (non-Javadoc)
79     * @see IEventTargetFactory#instantiateEventTarget(IEventTargetSpec, IHierarchicalEventTarget)
[545]80     */
[2146]81    @SuppressWarnings("unchecked")
[585]82    @Override
[2146]83    public <T extends IHierarchicalEventTarget> T instantiateEventTarget(IEventTargetSpec specification,
84                                                                         T                parent)
85        throws EventTargetModelConfigurationException
[592]86    {
[2146]87        if (!(specification instanceof IGUIElementSpec)) {
88            throw new IllegalArgumentException("can only handle IGUIElementSpecs as specification");
89        }
90       
91        if ((parent != null) && !(parent instanceof IGUIElement)) {
92            throw new IllegalArgumentException("can only handle IGUIElements as parent");
93        }
94       
95       return (T) instantiateEventTarget((IGUIElementSpec) specification, (IGUIElement) parent);
96    }
97       
98   
99    /**
100     * concrete implementation of {@link #instantiateEventTarget(IEventTargetSpec, IHierarchicalEventTarget)}
101     */
102    public IGUIElement instantiateEventTarget(IGUIElementSpec specification,
103                                              IGUIElement     parent)
104        throws EventTargetModelConfigurationException
105    {
[545]106        Properties mappings = getMappingsFromConfiguration();
[585]107        IGUIElement guiElement = null;
[990]108        String[] typeHierarchy = specification.getTypeHierarchy();
[984]109        int i = 0;
110        String className = null;
[1067]111       
112        while ((className == null) && (i < typeHierarchy.length)) {
113            className = mappings.getProperty(typeHierarchy[i]);
114            i++;
[984]115        }
[1067]116       
[545]117        if (className != null) {
118            try {
119                Class<?> clazz = this.getClass().getClassLoader().loadClass(className);
120
121                if (!IGUIElement.class.isAssignableFrom(clazz)) {
[724]122                    Console.traceln(Level.WARNING, "configured GUI element representing class " +
[831]123                        className + " is no valid GUIElement derivate.");
[545]124
125                    return null;
126                }
127
[604]128                Constructor<?> constructor = null;
129                Class<?> parentClass = (parent == null) ? null : parent.getClass();
[831]130
[604]131                // search for a constructor, that perfectly matches the types
132                for (Constructor<?> candidate : clazz.getConstructors()) {
[831]133                    if ((parentClass != null) && (candidate.getParameterTypes().length == 2) &&
[604]134                        (candidate.getParameterTypes()[0].equals(specification.getClass())) &&
135                        (candidate.getParameterTypes()[1].equals(parentClass)))
136                    {
137                        constructor = candidate;
138                        break;
139                    }
140                    else if (parentClass == null) {
141                        if ((candidate.getParameterTypes().length >= 1) &&
142                            (candidate.getParameterTypes()[0].equals(specification.getClass())))
143                        {
144                            constructor = candidate;
145                            break;
146                        }
147                    }
148                }
[831]149
[604]150                if (constructor == null) {
151                    // search for an assignable constructor
152                    for (Constructor<?> candidate : clazz.getConstructors()) {
153                        if ((candidate.getParameterTypes().length == 2) &&
154                            (candidate.getParameterTypes()[0].isInstance(specification)) &&
155                            (candidate.getParameterTypes()[1].isInstance(parent)))
156                        {
157                            constructor = candidate;
158                            break;
159                        }
160                    }
[831]161
[604]162                }
163               
164                if (constructor != null) {
165                    guiElement = (IGUIElement) constructor.newInstance(specification, parent);
166                }
167                else {
168                    throw new NoSuchMethodException
169                        ("no constructor with two parameters and assignable parameter types for " +
170                         specification.getClass() + " and " +
171                         (parent != null ? parent.getClass() : "null") + " found in class " +
172                         clazz);
173                }
[545]174
175            }
176            catch (ClassNotFoundException e) {
[724]177                Console.traceln(Level.WARNING, "configured GUI element representing class " +
178                                className + " can not be loaded.");
[2146]179                throw new EventTargetModelConfigurationException
[545]180                    ("configured GUI element representing class " + className +
181                     " can not be loaded.", e);
182            }
183            catch (SecurityException e) {
[724]184                Console.traceln(Level.WARNING, "configured GUI element representing class " +
185                                className + " can not be instantiated due to security reasons.");
[2146]186                throw new EventTargetModelConfigurationException
[545]187                    ("configured GUI element representing class " + className +
188                     " can not be instantiated due to security reasons.", e);
189            }
190            catch (NoSuchMethodException e) {
[724]191                Console.traceln(Level.WARNING, "configured GUI element representing class " +
192                                className + " does not provide an appropriate constructor.");
[2146]193                throw new EventTargetModelConfigurationException
[545]194                    ("configured GUI element representing class " + className +
[724]195                     " does not provide an appropriate constructor.", e);
[545]196            }
197            catch (IllegalArgumentException e) {
[724]198                Console.traceln(Level.WARNING, "configured GUI element representing class " +
199                                className + " does not provide an appropriate constructor " +
200                                "accepting the provided parameters.");
[2146]201                throw new EventTargetModelConfigurationException
[545]202                    ("configured GUI element representing class " + className + " does not " +
[724]203                     "provide an appropriate constructor accepting the provided parameters.", e);
[545]204            }
205            catch (InstantiationException e) {
[724]206                Console.traceln(Level.WARNING, "configured GUI element representing class " +
207                                className + " can not be instantiated.");
[2146]208                throw new EventTargetModelConfigurationException
[545]209                    ("configured GUI element representing class " + className +
210                     " can not be instantiated.", e);
211            }
212            catch (IllegalAccessException e) {
[724]213                Console.traceln(Level.WARNING, "configured GUI element representing class " +
214                                className + " can not be instantiated.");
[2146]215                throw new EventTargetModelConfigurationException
[545]216                    ("configured GUI element representing class " + className +
217                     " can not be instantiated.", e);
218            }
219            catch (InvocationTargetException e) {
[724]220                Console.traceln(Level.WARNING, "configured GUI element representing class " +
221                                className + " can not be instantiated.");
[2146]222                throw new EventTargetModelConfigurationException
[545]223                    ("configured GUI element representing class " + className +
224                     " can not be instantiated.", e);
225            }
226        }
[610]227       
228        if (guiElement == null ) {
[724]229            Console.traceln(Level.WARNING, "no class representing GUI elements of type " +
[739]230                            specification.getType() + " found. Please extend GUI element " +
[724]231                            "mapping files.");
[2146]232            throw new EventTargetModelConfigurationException
[610]233                ("no class representing GUI elements of type " + specification.getType() +
[739]234                 " found. Please extend GUI element mapping files");
[585]235        }
[545]236
[585]237        return guiElement;
[545]238    }
239
[2146]240    /* (non-Javadoc)
241     * @see IEventTargetFactory#instantiateGroup(String, IHierarchicalEventTarget, HierarchicalEventTargetModel)
242     */
243    @SuppressWarnings("unchecked")
244    @Override
245    public <T extends IHierarchicalEventTarget> T instantiateGroup(String                          groupName,
246                                                                   T                               parent,
247                                                                   HierarchicalEventTargetModel<T> hierarchicalEventTargetModel)
248    {
249        if (!(hierarchicalEventTargetModel instanceof GUIModel)) {
250            throw new IllegalArgumentException("can only handle GUI elements as event targets");
251        }
252       
253        if (!(parent instanceof IGUIElement)) {
254            throw new IllegalArgumentException("can only handle GUI elements as event targets");
255        }
256       
257        return (T) new GUIElementGroup
258              (groupName, (IGUIElement) parent, (GUIModel) hierarchicalEventTargetModel);
259    }
260
[545]261    /**
[831]262     * <p>
263     * Loads the mappings for GUI elements. All files that start with &quot;guimapping&quot;, end
[1796]264     * with &quot;.txt&quot;, and are located in the folder &quot;data/guimappings&quot; (relative
[831]265     * to the working directory) are loaded.
266     * </p>
[545]267     *
[831]268     * @return loaded GUI mappings
[545]269     */
[603]270    private synchronized Properties getMappingsFromConfiguration()
[2146]271        throws EventTargetModelConfigurationException
[603]272    {
[550]273        if (mappingsFromConfiguration != null) {
274            return mappingsFromConfiguration;
[545]275        }
276        else {
[550]277            mappingsFromConfiguration = new Properties();
[831]278
[585]279            File mappingsFolder = new File("data/guimappings");
[603]280            File[] children = mappingsFolder.listFiles();
[831]281
[603]282            if (children != null) {
283                for (File mappingsFile : children) {
284                    if (!mappingsFile.isDirectory() &&
285                        mappingsFile.getName().startsWith("guimapping") &&
286                        mappingsFile.getName().endsWith(".txt"))
287                    {
[744]288                        InputStream inStream = null;
[603]289                        try {
290                            inStream = new FileInputStream(mappingsFile);
291                            mappingsFromConfiguration.load(inStream);
292                        }
293                        catch (FileNotFoundException e) {
[2146]294                            throw new EventTargetModelConfigurationException
295                                ("could not read mapping configuration file " + mappingsFile, e);
[603]296                        }
297                        catch (IOException e) {
[2146]298                            throw new EventTargetModelConfigurationException
299                                ("could not read mapping configuration file " + mappingsFile, e);
[603]300                        }
[744]301                        finally {
302                            if (inStream != null) {
303                                try {
304                                    inStream.close();
305                                }
306                                catch (IOException e) {
307                                    // ignore
308                                }
309                            }
310                        }
[585]311                    }
[545]312                }
313            }
[603]314            else {
[2146]315                throw new EventTargetModelConfigurationException
316                    ("no GUI mappings file provided in folder " + mappingsFolder);
[603]317            }
[545]318
[550]319            return mappingsFromConfiguration;
[545]320        }
321    }
322}
Note: See TracBrowser for help on using the repository browser.