View Javadoc

1   package org.ximtec.igesture.tool.view.devicemanager;
2   
3   import java.awt.Point;
4   import java.io.File;
5   import java.io.IOException;
6   import java.lang.reflect.Constructor;
7   import java.lang.reflect.InvocationTargetException;
8   import java.util.ArrayList;
9   import java.util.Collection;
10  import java.util.HashMap;
11  import java.util.HashSet;
12  import java.util.List;
13  import java.util.Map;
14  import java.util.Set;
15  import java.util.Iterator;
16  import java.util.logging.Level;
17  import java.util.logging.Logger;
18  
19  import org.sigtec.graphix.GuiBundle;
20  import org.w3c.dom.Node;
21  import org.w3c.dom.NodeList;
22  import org.ximtec.igesture.io.AbstractGestureDevice;
23  import org.ximtec.igesture.io.DeviceDiscoveryService;
24  import org.ximtec.igesture.io.DeviceManagerListener;
25  import org.ximtec.igesture.io.DeviceUserAssociation;
26  import org.ximtec.igesture.io.GestureDevice;
27  import org.ximtec.igesture.io.IDeviceManager;
28  import org.ximtec.igesture.io.IUser;
29  import org.ximtec.igesture.io.User;
30  import org.ximtec.igesture.storage.IStorageManager;
31  import org.ximtec.igesture.storage.StorageEngine;
32  import org.ximtec.igesture.storage.StorageManager;
33  import org.ximtec.igesture.tool.GestureConstants;
34  import org.ximtec.igesture.tool.core.Controller;
35  import org.ximtec.igesture.tool.core.DefaultController;
36  import org.ximtec.igesture.tool.core.TabbedView;
37  import org.ximtec.igesture.tool.service.SwingMouseReaderService;
38  import org.ximtec.igesture.util.XMLParser;
39  
40  /**
41   * This class is an implementation of the controller of the Device Manager. It implements the {@link org.ximtec.igesture.io.IDeviceManager} interface.
42   * It also extends {@link org.ximtec.igesture.tool.core.DefaultController} to allow easy instantion by the main controller of the workbench.
43   * @author Bjorn Puype, bpuype@gmail.com
44   *
45   */
46  public class DeviceManagerController extends DefaultController implements IDeviceManager{
47  
48  	private static final Logger LOGGER = Logger.getLogger(DeviceManagerController.class.getName());
49  	
50  	/*
51  	 * device mapping: one user per device, what about tuio?
52  	 * */
53  	
54  	private Set<IUser> users = new HashSet<IUser>();
55  	private Set<AbstractGestureDevice<?,?>> devices = new HashSet<AbstractGestureDevice<?,?>>();
56  	private Map<AbstractGestureDevice<?,?>, IUser> userMapping = new HashMap<AbstractGestureDevice<?,?>,IUser>();
57  	
58  	private final Map<String, DeviceDiscoveryService> discoveryMapping = new HashMap<String,DeviceDiscoveryService>();
59  	private boolean enableAddDevicesAction = true;
60  	
61  	/** The system user is the default user and cannot be removed from the device manager */
62  	private IUser defaultUser;
63  	private AbstractGestureDevice<?, ?> defaultDevice;
64  	private DeviceManagerView view;
65  
66  	private List<DeviceManagerListener> listeners = new ArrayList<DeviceManagerListener>();
67  	
68  	/**
69  	 * Constructor
70  	 * @param parentController
71  	 * @param key
72  	 * @param guiBundle
73  	 */
74  	public DeviceManagerController(Controller parentController, String key, GuiBundle guiBundle) {
75  		super(parentController);
76  				
77  		//create the mapping between the connection types and the discovery services
78  		XMLParser parser = new XMLParser(){
79  
80  			@Override
81  			public void execute(ArrayList<NodeList> nodeLists) {
82  				
83  				try {
84  					String connection = ((Node)nodeLists.get(0).item(0)).getNodeValue();
85  					String className = ((Node)nodeLists.get(1).item(0)).getNodeValue();
86  					Class<?> c = Class.forName(className);
87  					
88  					Constructor<?> constructor = c.getConstructor();
89  					discoveryMapping.put(connection, (DeviceDiscoveryService)constructor.newInstance());
90  					
91  					LOGGER.log(Level.INFO,"Discovery Service Added: "+connection+" Discovery Service");
92  					
93  				} catch (ClassNotFoundException e) {
94  					LOGGER.log(Level.WARNING, "Discovery Service Class not found. The corresponding discovery service was not added.",e);
95  				} catch (SecurityException e) {
96  					LOGGER.log(Level.WARNING, "Discovery Service Class could not be instantiated. The corresponding discovery service was not added.",e);
97  				} catch (NoSuchMethodException e) {
98  					LOGGER.log(Level.WARNING, "Discovery Service Class could not be instantiated. The corresponding discovery service was not added.",e);
99  				} catch (IllegalArgumentException e) {
100 					LOGGER.log(Level.WARNING, "Discovery Service Class could not be instantiated. The corresponding discovery service was not added.",e);
101 				} catch (InstantiationException e) {
102 					LOGGER.log(Level.WARNING, "Discovery Service Class could not be instantiated. The corresponding discovery service was not added.",e);
103 				} catch (IllegalAccessException e) {
104 					LOGGER.log(Level.WARNING, "Discovery Service Class could not be instantiated. The corresponding discovery service was not added.",e);
105 				} catch (InvocationTargetException e) {
106 					LOGGER.log(Level.WARNING, "Discovery Service Class could not be instantiated. The corresponding discovery service was not added.",e);
107 				} catch (NullPointerException e) {
108 					LOGGER.log(Level.WARNING, "An empty node was encountered. The corresponding discovery service was not added.",e);
109 				}
110 			}
111 			
112 		};
113 		ArrayList<String> nodes = new ArrayList<String>();
114 		nodes.add("name");
115 		nodes.add("discoveryService");
116 		try {
117 			parser.parse(System.getProperty("user.dir")+System.getProperty("file.separator")+GestureConstants.XML_DISCOVERY, "connection", nodes);
118 		} catch (IOException e) {
119 			LOGGER.log(Level.SEVERE,"Could not find "+GestureConstants.XML_DISCOVERY +". Adding devices will be disabled",e);
120 			enableAddDevicesAction = false;
121 		} catch (Exception e) {
122 			LOGGER.log(Level.SEVERE,"Could not parse "+GestureConstants.XML_DISCOVERY +". Adding devices will be disabled",e);
123 			enableAddDevicesAction = false;
124 		}
125 		
126 		//instantiate the view
127 		view = new DeviceManagerView(this, key, guiBundle);
128 		
129 		//instantiate the default user/system user
130 		String userName = System.getProperty("user.name");
131 		defaultUser = new User(userName,userName.substring(0, 1));
132 		defaultDevice = (AbstractGestureDevice<?, ?>) parentController.getLocator().getService(SwingMouseReaderService.IDENTIFIER);
133 		
134 		//add the default user and the mouse.
135 		addUser(defaultUser);
136 		addDevice(defaultDevice,defaultUser);
137 	}
138 	
139 	/**
140 	 * This method returns true if the add devices action should be enabled
141 	 * @return
142 	 */
143 	public boolean getEnableAddDevicesAction()
144 	{
145 		/*
146 		 * enableAddDevicesAction is false when connections.xml could not be found or parsed
147 		 * even if the file could be parsed, it is possible that the mentionned discovery classes are incorrect
148 		 * and no services were added to the mapping
149 		 * in both cases, adding devices is not possible
150 		 */
151 		return (enableAddDevicesAction || !discoveryMapping.isEmpty());
152 	}
153 
154 	@Override
155 	public TabbedView getView() {
156 		return null;
157 	}
158 
159 	@Override
160 	public void addDevice(AbstractGestureDevice<?,?> device, IUser user) {
161 		if(!devices.contains(device))
162 		{
163 			devices.add(device);
164 			DeviceUserAssociation ass = new DeviceUserAssociation(device,user);
165 			if(!userMapping.containsKey(device))
166 			{
167 				userMapping.put(device, user);
168 			}
169 			view.addDevice(ass);
170 			notifyDeviceManagerListener(DeviceManagerListener.ADD,device);
171 			LOGGER.log(Level.INFO,"Device Added: "+ ass);
172 		}
173 	}
174 
175 	@Override
176 	public void addUser(IUser user) {
177 		if(!users.contains(user))
178 		{
179 			users.add(user);
180 			view.addUser(user);
181 			
182 			LOGGER.log(Level.INFO,"User Added: "+ user);
183 		}
184 	}
185 
186 	@Override
187 	public IUser getDefaultUser() {
188 		return defaultUser;
189 	}
190 
191 	@Override
192 	public Set<AbstractGestureDevice<?,?>> getDevices() {
193 		return devices;
194 	}
195 
196 	@Override
197 	public Set<IUser> getUsers() {
198 		return users;
199 	}
200 
201 	@Override
202 	public void removeDevice(AbstractGestureDevice<?,?> device) {
203 		
204 		
205 		//TODO als actie luistert naar selecties, kan je hem disablen zodat nooit defaultmouse wordt verwijderd
206 		if(!device.isDefaultDevice())//no removal of system mouse / default devices
207 		{
208 			view.removeDevice();
209 			devices.remove(device);
210 			userMapping.remove(device);
211 			notifyDeviceManagerListener(DeviceManagerListener.REMOVE,device);
212 			LOGGER.log(Level.INFO, "Device Removed: "+ device);
213 		}
214 				
215 	}
216 
217 	@Override
218 	public void removeUser(IUser user) {
219 		
220 		
221 		//TODO als actie luistert naar selecties, kan je hem disablen zodat nooit defaultuser wordt verwijderd
222 		if(!defaultUser.equals(user))//system user may not be removed
223 		{
224 			view.removeUser();
225 			users.remove(user);
226 			//reassociate the devices that had this user to the default user
227 			if(userMapping.containsValue(user))
228 			{
229 				//remove user, update bindings behavior (new user of device is default user)
230 				Set<AbstractGestureDevice<?,?>> keys = userMapping.keySet();
231 				for(AbstractGestureDevice<?,?> d : keys)
232 				{
233 					if(userMapping.get(d).equals(user))
234 					{
235 						userMapping.put(d, getDefaultUser());
236 						
237 						Collection<DeviceUserAssociation> list = view.getDevices();
238 						for(Iterator<DeviceUserAssociation> iter = list.iterator(); iter.hasNext(); )
239 						{
240 							DeviceUserAssociation ass = iter.next();
241 							if(ass.getUserItem().equals(user))
242 							{
243 								view.updateDevice(getDefaultUser(), DeviceManagerView.COL_DEVICE_USER, ass);
244 								break;
245 							}
246 						}						
247 					}
248 				}
249 				
250 				LOGGER.log(Level.INFO,"User Removed: "+ user);
251 			}
252 		}
253 	}
254 
255 	@Override
256 	public void associateUser(AbstractGestureDevice<?,?> device, IUser user) {
257 		
258 			view.updateDevice(user,DeviceManagerView.COL_DEVICE_USER, view.getSelectedDevice());
259 			userMapping.put(device, user);
260 			
261 			LOGGER.log(Level.INFO,"Associated User '"+user+"' with Device '"+device+"'");
262 	}
263 
264 	@Override
265 	public void showView(Point p) {
266 		view.setLocation(p);
267 		view.setVisible(true);		
268 	}
269 
270 	@Override
271 	public void saveConfiguration(File file)
272 	{
273 		//DB4O storage engine is used
274 		StorageEngine engine = StorageManager.createStorageEngine(file);
275 		IStorageManager storageManager = new StorageManager(engine);
276 		// save the users
277 		for(IUser user : users)
278 			storageManager.store((User)user);
279 		//save the devices and association
280 		for(DeviceUserAssociation ass : view.getDevices())
281 			storageManager.store(ass);		
282 		
283 		storageManager.commit();
284 		storageManager.dispose();
285 		
286 		LOGGER.log(Level.INFO, "Saved Device-User Configuration: "+file.toString());
287 	}
288 
289 	@Override
290 	public void loadConfiguration(File file)
291 	{
292 		//DB4O storage engine is used
293 		StorageEngine engine = StorageManager.createStorageEngine(file);
294 		IStorageManager storageManager = new StorageManager(engine);
295 		//get the users from file
296 		List<User> users = storageManager.load(User.class);
297 		//get the associations from file
298 		List<DeviceUserAssociation> associations = storageManager.load(DeviceUserAssociation.class);
299 		storageManager.dispose();
300 		
301 		//remove users and devices except the default ones
302 		for(AbstractGestureDevice<?,?> device : devices)
303 		{
304 			if(!device.isDefaultDevice())
305 				removeDevice(device);
306 		}
307 		for(User user : users)
308 		{
309 			if(!user.equals(defaultUser))
310 				removeUser(user);
311 		}
312 		
313 		// load users
314 		for(User user : users)
315 		{
316 			if(!user.equals(defaultUser))
317 				addUser(user);
318 		}
319 		// load devices and association
320 		for(DeviceUserAssociation ass : associations)
321 		{
322 			if(!ass.getDeviceItem().isDefaultDevice())
323 			{
324 				ass.getDeviceItem().setIsConnected(false);
325 				ass.getDeviceItem().connect();
326 				addDevice(ass.getDeviceItem(),ass.getUserItem());
327 			} 
328 			else 
329 			{
330 				//TODO if SwingMouseReaderService is not referenced anywhere in hardcoded way this is not necessary anymore
331 				// for system mouse, keep current SwingMouseReaderService
332 				// if it was previously associated with the system user, use current system user object
333 				IUser u = null;
334 				if(!ass.getUserItem().equals(defaultUser))
335 					u = defaultUser;
336 				else // else use the associated user
337 					u = ass.getUserItem();
338 				associateUser(defaultDevice, u);
339 			}
340 		}
341 		
342 		LOGGER.log(Level.INFO, "Loaded Device-User Configuration: "+file.toString());
343 	}
344 	
345 	/**
346 	 * Clear the users, devices and device-user mapping.
347 	 */
348 	private void cleanup()
349 	{
350 		users.clear();
351 		devices.clear();
352 		userMapping.clear();
353 //		view.clear();
354 	}
355 	
356 	@Override
357 	public Map<String, DeviceDiscoveryService> getDiscoveryMapping()
358 	{
359 		return discoveryMapping;
360 	}
361 	
362 	public void addDeviceManagerListener(DeviceManagerListener listener)
363 	{
364 		listeners.add(listener);
365 	}
366 	
367 	public void removeDeviceManagerListener(DeviceManagerListener listener)
368 	{
369 		listeners.remove(listener);
370 	}
371 	
372 	public void removeAllDeviceManagerListener()
373 	{
374 		listeners.clear();
375 	}
376 	
377 	public void notifyDeviceManagerListener(int operation, AbstractGestureDevice<?,?> device)
378 	{
379 		for(DeviceManagerListener listener : listeners)
380 		{
381 			listener.updateDeviceManagerListener(operation, device);
382 		}
383 	}
384 
385 	@Override
386 	public IUser getAssociatedUser(GestureDevice<?, ?> device) {
387 		return userMapping.get((AbstractGestureDevice<?,?>)device);
388 	}
389 	
390 	public boolean areInitialsValid(String initials)
391 	{
392 		boolean valid = true;
393 		for(IUser user: users)
394 		{
395 			if(user.getInitials().equals(initials))
396 			{
397 				valid = false;
398 				break;
399 			}
400 		}
401 		return valid;
402 	}
403 }