View Javadoc

1   /*
2    * @(#)$Id: DefaultController.java 747 2009-08-16 00:09:28Z bsigner $
3    *
4    * Author		:	Ueli Kurmann, igesture@uelikurmann.ch
5    *                  
6    *
7    * Purpose		:   Default implementation of the controller interface.
8    *
9    * -----------------------------------------------------------------------
10   *
11   * Revision Information:
12   *
13   * Date				Who			Reason
14   *
15   * 09.04.2008       ukurmann	Initial Release
16   *
17   * -----------------------------------------------------------------------
18   *
19   * Copyright 1999-2009 ETH Zurich. All Rights Reserved.
20   *
21   * This software is the proprietary information of ETH Zurich.
22   * Use is subject to license terms.
23   * 
24   */
25  
26  
27  package org.ximtec.igesture.tool.core;
28  
29  import java.beans.PropertyChangeEvent;
30  import java.lang.reflect.Method;
31  import java.util.ArrayList;
32  import java.util.HashMap;
33  import java.util.List;
34  import java.util.Map;
35  import java.util.concurrent.Executors;
36  import java.util.logging.Logger;
37  
38  import javax.swing.SwingUtilities;
39  
40  import org.sigtec.util.Constant;
41  import org.ximtec.igesture.tool.locator.Locator;
42  
43  
44  /**
45   * Default implementation of the controller interface.
46   * 
47   * @version 1.0 09.04.2008
48   * @author Ueli Kurmann, igesture@uelikurmann.ch
49   * @author Beat Signer, bsigner@vub.ac.be
50   */
51  public abstract class DefaultController implements Controller {
52  
53     private static final Logger LOGGER = Logger.getLogger(DefaultController.class
54           .getName());
55  
56     private Map<String, Method> commandMethods;
57  
58     private List<Controller> controllers;
59  
60     private Controller parent;
61  
62     private Map<String, LocateableAction> actions;
63  
64     private Locator locator;
65  
66  
67     public DefaultController(Controller parentController) {
68        controllers = new ArrayList<Controller>();
69        actions = new HashMap<String, LocateableAction>();
70        this.setParent(parentController);
71        commandMethods = new HashMap<String, Method>();
72  
73        for (Method method : this.getClass().getDeclaredMethods()) {
74  
75           if (method.isAnnotationPresent(ExecCmd.class)) {
76              commandMethods.put(method.getAnnotation(ExecCmd.class).name(),
77                    method);
78           }
79  
80        }
81  
82     }
83  
84  
85     /*
86      * (non-Javadoc)
87      * 
88      * @see org.ximtec.igesture.tool.core.Controller#addController(org.ximtec.igesture
89      *      .tool.core.Controller)
90      */
91     @Override
92     public void addController(Controller controller) {
93        if ((controller.getParent() != null) && (controller.getParent() != this)) {
94           throw new RuntimeException("Controller should have only one parent.");
95        }
96        else {
97           controller.setParent(this);
98        }
99  
100       controllers.add(controller);
101    } // addController
102 
103 
104    /*
105     * (non-Javadoc)
106     * 
107     * @see org.ximtec.igesture.tool.core.Controller#getControllers()
108     */
109    @Override
110    public List<Controller> getControllers() {
111       return controllers;
112    } // getControllers
113 
114 
115    /*
116     * (non-Javadoc)
117     * 
118     * @see org.ximtec.igesture.tool.core.Controller#removeAllController()
119     */
120    @Override
121    public void removeAllControllers() {
122       controllers.clear();
123    }
124 
125 
126    @Override
127    public void removeController(Controller controller) {
128       controllers.remove(controller);
129    }
130 
131 
132    @Override
133    public final void execute(final Command command) {
134       if (SwingUtilities.isEventDispatchThread()) {
135          invokeInWorkerThread(command);
136          return;
137       }
138 
139       if ((command != null) && (command.getCommand() != null)) {
140 
141          if (!invokeCommand(command)) {
142             LOGGER.info("Command not handled in " + this.getClass().getName()
143                   + ". " + Constant.SINGLE_QUOTE + command.getCommand()
144                   + Constant.SINGLE_QUOTE);
145 
146             // if command execution fails, try to execute it in the parent
147             // controller
148             if (parent != null) {
149                parent.execute(command);
150             }
151 
152          }
153 
154       }
155       else {
156          LOGGER.warning("Command " + Constant.SINGLE_QUOTE + command
157                + Constant.SINGLE_QUOTE + "not available.");
158       }
159 
160    } // execute
161 
162 
163    /**
164     * Invokes a command in the worker thread.
165     * 
166     * @param command
167     */
168    private void invokeInWorkerThread(final Command command) {
169       LOGGER.info("Dispatch event dispatch thread to a worker thread.");
170       Executors.newSingleThreadExecutor().execute(new Runnable() {
171 
172          @Override
173          public void run() {
174             execute(command);
175          }
176 
177       });
178    }
179 
180 
181    @Override
182    public void propertyChange(final PropertyChangeEvent event) {
183       for (final Controller controller : getControllers()) {
184 
185          if (SwingUtilities.isEventDispatchThread()) {
186             controller.propertyChange(event);
187          }
188          else {
189             SwingUtilities.invokeLater(new Runnable() {
190 
191                @Override
192                public void run() {
193                   controller.propertyChange(event);
194 
195                }
196 
197             });
198          }
199 
200       }
201    }
202 
203 
204    /**
205     * Invokes a command
206     * 
207     * @param object
208     * @param command
209     * @return
210     */
211    private boolean invokeCommand(Command command) {
212       LOGGER.info("Invoke " + Constant.SINGLE_QUOTE + command
213             + Constant.SINGLE_QUOTE);
214       Method method = commandMethods.get(command.getCommand());
215 
216       if (method != null) {
217          try {
218             if (!method.isAccessible()) {
219                method.setAccessible(true);
220             }
221 
222             if (method.getParameterTypes().length == 0) {
223                method.invoke(this);
224             }
225             else {
226                method.invoke(this, command);
227             }
228 
229             LOGGER.info("Command invoked. " + command.getCommand());
230             return true;
231          }
232          catch (Exception e) {
233             LOGGER.warning("Could not execute command. " + command.getCommand()
234                   + e.getMessage());
235          }
236 
237       }
238       else {
239          LOGGER.warning("Command not defined. " + command.getCommand());
240       }
241 
242       return false;
243    }
244 
245 
246    @Override
247    public Controller getParent() {
248       return parent;
249    }
250 
251 
252    @Override
253    public void setParent(Controller controller) {
254       this.parent = controller;
255 
256    }
257 
258 
259    @Override
260    public LocateableAction getAction(String actionName) {
261       return actions.get(actionName);
262    }
263 
264 
265    public void addAction(String actionName, LocateableAction action) {
266       actions.put(actionName, action);
267    }
268 
269 
270    @Override
271    public Locator getLocator() {
272       if (locator != null) {
273          return locator;
274       }
275       else if (getParent() != null) {
276          return getParent().getLocator();
277       }
278 
279       return null;
280    }
281 
282 
283    public void setLocator(Locator locator) {
284       this.locator = locator;
285    }
286 
287 
288    /**
289     * Returns true if this is the root controller.
290     * 
291     * @return
292     */
293    public boolean isRoot() {
294       return (getParent() == null);
295    } // isRoot
296 
297 }