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

Last change on this file since 990 was 990, checked in by pharms, 12 years ago
  • rename of GUI element class hierarchy to type hierarchy, as the other method is also called "getType"
  • corrected some implementations of "getTypeHierarchy" which were not implemented so far.
File size: 11.8 KB
Line 
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.
14
15package de.ugoe.cs.autoquest.eventcore.guimodel;
16
17import java.io.File;
18import java.io.FileInputStream;
19import java.io.FileNotFoundException;
20import java.io.IOException;
21import java.io.InputStream;
22import java.lang.reflect.Constructor;
23import java.lang.reflect.InvocationTargetException;
24import java.util.Properties;
25import java.util.logging.Level;
26
27import de.ugoe.cs.util.console.Console;
28
29/**
30 * <p>
31 * Creates {@link IGUIElement}s from a given specification. Implemented as singleton.
32 * </p>
33 *
34 * @version 1.0
35 * @author Patrick Harms
36 */
37public class GUIElementFactory implements IGUIElementFactory {
38
39    /**
40     * <p>
41     * Instance of the class (singleton)
42     * </p>
43     */
44    private static GUIElementFactory instance = new GUIElementFactory();
45
46    /**
47     * <p>
48     * Constructor. Creates a new GUIElementFactory. Private to preserve singleton property.
49     * </p>
50     */
51    private GUIElementFactory() {}
52
53    /**
54     * <p>
55     * Returns the instance of this class.
56     * </p>
57     *
58     * @return the instance
59     */
60    public static synchronized GUIElementFactory getInstance() {
61        return instance;
62    }
63
64    /**
65     * <p>
66     * A property mapping that defines to which Java class is created given the type of the GUI
67     * element found in the specification.
68     * </p>
69     */
70    private Properties mappingsFromConfiguration;
71
72   
73    /*
74     * (non-Javadoc)
75     *
76     * @see
77     * de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementFactory#instantiateGUIElement(de.ugoe.cs.autoquest
78     * .eventcore.guimodel.IGUIElementSpec, de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement)
79     */
80    @Override
81    public IGUIElement instantiateGUIElement(IGUIElementSpec specification, IGUIElement parent)
82        throws GUIModelConfigurationException
83    {
84        Properties mappings = getMappingsFromConfiguration();
85        IGUIElement guiElement = null;
86        String[] typeHierarchy = specification.getTypeHierarchy();
87        int i = 0;
88        String className = null;
89        while (className == null && i < typeHierarchy.length){
90                className = mappings.getProperty(typeHierarchy[i]);
91                i++;
92        }
93        if (className != null) {
94            try {
95                Class<?> clazz = this.getClass().getClassLoader().loadClass(className);
96
97                if (!IGUIElement.class.isAssignableFrom(clazz)) {
98                    Console.traceln(Level.WARNING, "configured GUI element representing class " +
99                        className + " is no valid GUIElement derivate.");
100
101                    return null;
102                }
103
104                Constructor<?> constructor = null;
105                Class<?> parentClass = (parent == null) ? null : parent.getClass();
106
107                // search for a constructor, that perfectly matches the types
108                for (Constructor<?> candidate : clazz.getConstructors()) {
109                    if ((parentClass != null) && (candidate.getParameterTypes().length == 2) &&
110                        (candidate.getParameterTypes()[0].equals(specification.getClass())) &&
111                        (candidate.getParameterTypes()[1].equals(parentClass)))
112                    {
113                        constructor = candidate;
114                        break;
115                    }
116                    else if (parentClass == null) {
117                        if ((candidate.getParameterTypes().length >= 1) &&
118                            (candidate.getParameterTypes()[0].equals(specification.getClass())))
119                        {
120                            constructor = candidate;
121                            break;
122                        }
123                    }
124                }
125
126                if (constructor == null) {
127                    // search for an assignable constructor
128                    for (Constructor<?> candidate : clazz.getConstructors()) {
129                        if ((candidate.getParameterTypes().length == 2) &&
130                            (candidate.getParameterTypes()[0].isInstance(specification)) &&
131                            (candidate.getParameterTypes()[1].isInstance(parent)))
132                        {
133                            constructor = candidate;
134                            break;
135                        }
136                    }
137
138                }
139               
140                if (constructor != null) {
141                    guiElement = (IGUIElement) constructor.newInstance(specification, parent);
142                }
143                else {
144                    throw new NoSuchMethodException
145                        ("no constructor with two parameters and assignable parameter types for " +
146                         specification.getClass() + " and " +
147                         (parent != null ? parent.getClass() : "null") + " found in class " +
148                         clazz);
149                }
150
151            }
152            catch (ClassNotFoundException e) {
153                Console.traceln(Level.WARNING, "configured GUI element representing class " +
154                                className + " can not be loaded.");
155                throw new GUIModelConfigurationException
156                    ("configured GUI element representing class " + className +
157                     " can not be loaded.", e);
158            }
159            catch (SecurityException e) {
160                Console.traceln(Level.WARNING, "configured GUI element representing class " +
161                                className + " can not be instantiated due to security reasons.");
162                throw new GUIModelConfigurationException
163                    ("configured GUI element representing class " + className +
164                     " can not be instantiated due to security reasons.", e);
165            }
166            catch (NoSuchMethodException e) {
167                Console.traceln(Level.WARNING, "configured GUI element representing class " +
168                                className + " does not provide an appropriate constructor.");
169                throw new GUIModelConfigurationException
170                    ("configured GUI element representing class " + className +
171                     " does not provide an appropriate constructor.", e);
172            }
173            catch (IllegalArgumentException e) {
174                Console.traceln(Level.WARNING, "configured GUI element representing class " +
175                                className + " does not provide an appropriate constructor " +
176                                "accepting the provided parameters.");
177                throw new GUIModelConfigurationException
178                    ("configured GUI element representing class " + className + " does not " +
179                     "provide an appropriate constructor accepting the provided parameters.", e);
180            }
181            catch (InstantiationException e) {
182                Console.traceln(Level.WARNING, "configured GUI element representing class " +
183                                className + " can not be instantiated.");
184                throw new GUIModelConfigurationException
185                    ("configured GUI element representing class " + className +
186                     " can not be instantiated.", e);
187            }
188            catch (IllegalAccessException e) {
189                Console.traceln(Level.WARNING, "configured GUI element representing class " +
190                                className + " can not be instantiated.");
191                throw new GUIModelConfigurationException
192                    ("configured GUI element representing class " + className +
193                     " can not be instantiated.", e);
194            }
195            catch (InvocationTargetException e) {
196                Console.traceln(Level.WARNING, "configured GUI element representing class " +
197                                className + " can not be instantiated.");
198                throw new GUIModelConfigurationException
199                    ("configured GUI element representing class " + className +
200                     " can not be instantiated.", e);
201            }
202        }
203       
204        if (guiElement == null ) {
205            Console.traceln(Level.WARNING, "no class representing GUI elements of type " +
206                            specification.getType() + " found. Please extend GUI element " +
207                            "mapping files.");
208            throw new GUIModelConfigurationException
209                ("no class representing GUI elements of type " + specification.getType() +
210                 " found. Please extend GUI element mapping files");
211        }
212
213        return guiElement;
214    }
215
216    /**
217     * <p>
218     * Loads the mappings for GUI elements. All files that start with &quot;guimapping&quot;, end
219     * with &quot;.txt&quot;, and are located in the folter &quot;data/guimappings&quot; (relative
220     * to the working directory) are loaded.
221     * </p>
222     *
223     * @return loaded GUI mappings
224     */
225    private synchronized Properties getMappingsFromConfiguration()
226        throws GUIModelConfigurationException
227    {
228        if (mappingsFromConfiguration != null) {
229            return mappingsFromConfiguration;
230        }
231        else {
232            mappingsFromConfiguration = new Properties();
233
234            File mappingsFolder = new File("data/guimappings");
235            File[] children = mappingsFolder.listFiles();
236
237            if (children != null) {
238                for (File mappingsFile : children) {
239                    if (!mappingsFile.isDirectory() &&
240                        mappingsFile.getName().startsWith("guimapping") &&
241                        mappingsFile.getName().endsWith(".txt"))
242                    {
243                        InputStream inStream = null;
244                        try {
245                            inStream = new FileInputStream(mappingsFile);
246                            mappingsFromConfiguration.load(inStream);
247                        }
248                        catch (FileNotFoundException e) {
249                            throw new GUIModelConfigurationException(
250                                                                     "could not read mapping configuration file " +
251                                                                         mappingsFile, e);
252                        }
253                        catch (IOException e) {
254                            throw new GUIModelConfigurationException(
255                                                                     "could not read mapping configuration file " +
256                                                                         mappingsFile, e);
257                        }
258                        finally {
259                            if (inStream != null) {
260                                try {
261                                    inStream.close();
262                                }
263                                catch (IOException e) {
264                                    // ignore
265                                }
266                            }
267                        }
268                    }
269                }
270            }
271            else {
272                throw new GUIModelConfigurationException(
273                                                         "no GUI mappings file provided in folder " +
274                                                             mappingsFolder);
275            }
276
277            return mappingsFromConfiguration;
278        }
279    }
280}
Note: See TracBrowser for help on using the repository browser.