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

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