001 package users;
002
003 import java.io.*;
004
005 import java.util.*;
006
007 import users.events.*;
008 import users.swing.*;
009
010 import util.*;
011
012 /**
013 * Manages users, their capabilities and their associations to other objects.
014 *
015 * <p>The UserManager provides possibilities to manage any number of users. Users can
016 * be added, retrieved using their name to identify them, and removed from the system.
017 * Additionally, users can be associated to, and disassociated from, any object. Their can be a maximum of
018 * one user associated to any given object at any given time.</p>
019 *
020 * <p>You can provide a set of default capabilities, that every new user will be provided with.</p>
021 *
022 * @see User
023 * @see #setDefaultCaps
024 * @see sale.SalesPoint
025 * @see #logOn
026 *
027 * @author Steffen Zschaler
028 * @version 2.0 05/05/1999
029 * @since v2.0
030 */
031 public class UserManager extends Object implements Serializable {
032
033 /**
034 * The map used to store all the users managed by this UserManager.
035 *
036 * <p>The user's name is being used as the key. The user itself is being stored as
037 * the value.</p>
038 *
039 * @see User
040 *
041 * @serial
042 */
043 private SortedMap m_mpUsers = new TreeMap();
044
045 /**
046 * The map used to store all the users currently associated to some object.
047 *
048 * <p>The key of the map is the object to which a given user is associated.
049 * The user itself is being stored as the value.</p>
050 *
051 * @see User
052 * @see #logOn
053 *
054 * @serial
055 */
056 private Map m_mpCurrentUsers = new HashMap();
057
058 /**
059 * The map of default capabilities to be associated with each new user.
060 *
061 * <p>The keys and values are being used in the same way as {@link User} uses them, i.e.
062 * the capabilities names are used as keys and the capabilities themselves as
063 * values.</p>
064 *
065 * @see #setDefaultCaps
066 * @see Capability
067 * @see User#setCapabilities
068 *
069 * @serial
070 */
071 private Map m_mpDefaultCaps = new HashMap();
072
073 /**
074 * The factory used to create new User objects.
075 *
076 * @see #createUser
077 * @see #setUserCreator
078 * @see User
079 *
080 * @serial
081 */
082 private UserCreator m_ucCreator;
083
084 /**
085 * The list of listeners registered with this UserManager.
086 *
087 * @serial See <a href="#util.ListenerHelper">ListenerHelper's serializable form</a> for more information on
088 * what listeners get a chance to be serialized.
089 */
090 protected ListenerHelper m_lhListeners = new ListenerHelper();
091
092 /**
093 * Create a new UserManager with an empty set of default capabilities, managing direct
094 * instances of the User class.
095 *
096 * @see #setDefaultCaps
097 * @see #createUser
098 */
099 public UserManager() {
100 this(null, null);
101 }
102
103 /**
104 * Create a new UserManager, using a specific set of default capabilities. This
105 * UserManager will manage direct instances of User.
106 *
107 * @param mpDefaultCaps a map describing the default capabilities any new user should
108 * have. The keys of this map should be the name of their associated capability. Specifying
109 * <code>null</code> will result in there being no default capabilities.
110 *
111 * @see #setDefaultCaps
112 * @see #createUser
113 * @see Capability
114 */
115 public UserManager(Map mpDefaultCaps) {
116 this(mpDefaultCaps, null);
117 }
118
119 /**
120 * Create a new UserManager with an empty set of default capabilities. This UserManager
121 * will create instances of a developer defined subclass of User.
122 *
123 * @param ucCreator the factory to be used to create new User objects. Specifying
124 * <code>null</code> will result in a default implementation being used, which will
125 * create direct instances of the User class.
126 *
127 * @see #setDefaultCaps
128 * @see #createUser
129 */
130 public UserManager(UserCreator ucCreator) {
131 this(null, ucCreator);
132 }
133
134 /**
135 * Create a new UserManager providing both a set of default capabilities and a User
136 * creation factory.
137 *
138 * @param mpDefaultCaps a map describing the default capabilities any new user should
139 * have. The keys of this map should be the name of their associated capability. Specifying
140 * <code>null</code> will result in there being no default capabilities.
141 * @param ucCreator the factory to be used to create new User objects. Specifying
142 * <code>null</code> will result in a default implementation being used, which will
143 * create direct instances of the User class.
144 *
145 * @see #setDefaultCaps
146 * @see Capability
147 * @see #createUser
148 * @see User
149 */
150 public UserManager(Map mpDefaultCaps, UserCreator ucCreator) {
151 super();
152
153 setDefaultCaps(mpDefaultCaps);
154 setUserCreator(ucCreator);
155 }
156
157 /**
158 * Set the factory to be used when creating new User objects.
159 *
160 * @param ucCreator the factory to be used to create new User objects. Specifying
161 * <code>null</code> will result in a default implementation being used, which will
162 * create direct instances of the User class.
163 *
164 * @see #createUser
165 * @see User
166 *
167 * @override Never
168 */
169 public synchronized void setUserCreator(UserCreator ucCreator) {
170 if (ucCreator != null) {
171 m_ucCreator = ucCreator;
172 } else {
173 m_ucCreator = new UserCreator();
174 }
175 }
176
177 /**
178 * Specify the set of default capabilities to be used when creating new User objects.
179 *
180 * <p>Calling this method will not influence the capabilities of users already created.</p>
181 *
182 * @param mpDefaultCaps a map describing the default capabilities any new user should
183 * have. The keys of this map should be the name of their associated capability. Specifying
184 * <code>null</code> will result in there being no default capabilities.
185 *
186 * @see #createUser
187 * @see Capability
188 *
189 * @override Never
190 */
191 public synchronized void setDefaultCaps(Map mpDefaultCaps) {
192 if (mpDefaultCaps != null) {
193 m_mpDefaultCaps = new HashMap(mpDefaultCaps);
194 } else {
195 m_mpDefaultCaps = new HashMap();
196 }
197 }
198
199 /**
200 * Set a capability to be used as a default capability henceforward.
201 *
202 * <p>Calling this method will not influence the capabilities of users already created.</p>
203 *
204 * <p>If a default capability of the same name as the one given did already exist, it
205 * will be replaced by the new capability.</p>
206 *
207 * @param cap the capability to be set as a default capability.
208 *
209 * @see #createUser
210 *
211 * @override Never
212 */
213 public synchronized void setDefaultCapability(Capability cap) {
214 m_mpDefaultCaps.put(cap.getName(), cap);
215 }
216
217 /**
218 * Create a new user to be managed by this UserManager.
219 *
220 * <p>This method uses the defined {@link UserCreator} (see {@link #setUserCreator}) to create the
221 * new <code>User</code> object. The new user will later be accessible using its name.</p>
222 *
223 * <p>The newly created user will get all the default capabilities defined at the time
224 * this method is called.</p>
225 *
226 * <p>A <code>userAdded</code> event will be received by any {@link UserDataListener} that
227 * registered an interest in this <code>UserManager</code>.</p>
228 *
229 * @param sName the name of the new user. This must be unique, i.e. there must not be
230 * a user with the same name already managed by this UserManager.
231 *
232 * @return the newly created user.
233 *
234 * @exception DuplicateUserException if there already was a user with the given name.
235 *
236 * @see #setDefaultCaps
237 * @see #setUserCreator
238 * @see User
239 * @see UserCreator#createUser
240 * @see users.events.UserDataListener#userAdded
241 *
242 * @override Never Rather than overriding this method, you should provide a new {@link UserCreator}.
243 */
244 public synchronized User createUser(String sName) {
245
246 if (m_mpUsers.containsKey(sName)) {
247 throw new DuplicateUserException("User \"" + sName +
248 "\" already exists ! Cannot have two users with the same user name.");
249 }
250
251 User usr = m_ucCreator.createUser(sName);
252
253 usr.setCapabilities(m_mpDefaultCaps);
254
255 m_mpUsers.put(sName, usr);
256
257 fireUserAdded(usr);
258
259 return usr;
260 }
261
262 /**
263 * Add a user to the UserManager.
264 *
265 * <p>A <code>userAdded</code> event will be received by any {@link UserDataListener} that
266 * registered an interest in this UserManager.</p>
267 *
268 * @param usr the user to be added.
269 *
270 * @exception DuplicateUserException if there already is a user of the same name.
271 *
272 * @see users.events.UserDataListener#userAdded
273 *
274 * @override Never
275 */
276 public synchronized void addUser(User usr) {
277
278 if (m_mpUsers.containsKey(usr.getName())) {
279 throw new DuplicateUserException("User \"" + usr.getName() +
280 "\" already exists ! Cannot have two users with the same user name.");
281 }
282
283 m_mpUsers.put(usr.getName(), usr);
284
285 fireUserAdded(usr);
286 }
287
288 /**
289 * Retrieve a user by name.
290 *
291 * <p>If no user with the given name exists, this method will return <code>null</code>.</p>
292 *
293 * @param sName the name of the user looked for.
294 *
295 * @return the user corresponding to the given name, if any. <code>null</code> will
296 * be returned if no such user can be found.
297 *
298 * @see #createUser
299 *
300 * @override Never
301 */
302 public synchronized User getUser(String sName) {
303 return (User)m_mpUsers.get(sName);
304 }
305
306 /**
307 * Return all user names registered with this UserManager.
308 *
309 * <p>The returned set is backed by the UserManager, i.e. it will reflect changes
310 * made through <code>createUser()</code> or <code>removeUser()</code>. The set itself
311 * is unmodifiable and ordered alphabetically.</p>
312 *
313 * @return an unmodifiable, ordered set of all user names in this UserManager.
314 *
315 * @see #createUser
316 * @see #deleteUser
317 *
318 * @override Never
319 */
320 public synchronized Set getUserNames() {
321 return Collections.unmodifiableSet(m_mpUsers.keySet());
322 }
323
324 /**
325 * Return all users registered with this UserManager.
326 *
327 * <p>The returned collection is backed by the UserManager, i.e. it will reflect
328 * changes made through <code>createUser()</code> or <code>removeUser()</code>. The
329 * collection itself is unmodifiable and ordered alphabetically by the users' names.</p>
330 *
331 * @return an unmodifiable, ordered set of all users in this UserManager.
332 *
333 * @see #createUser
334 * @see #deleteUser
335 *
336 * @override Never
337 */
338 public synchronized Collection getUsers() {
339 return Collections.unmodifiableCollection(m_mpUsers.values());
340 }
341
342 /**
343 * Delete a user from this UserManager.
344 *
345 * <p>The user will be removed from the UserManager and will no longer be available
346 * via {@link #getUser}. A <code>userDeleted</code> event will be received by all
347 * {@link UserDataListener UserDataListeners} registered with this UserManager if a user was removed. If no user
348 * with the given name existed no exception will be thrown and no event will be fired.</p>
349 *
350 * <p>If the user is currently associated to some object, it will stay so until
351 * it is disassociated explicitly. It will not have the possibility to log in again,
352 * though.</p>
353 *
354 * @param sName the name of the user to be removed
355 *
356 * @return the user that was just removed or <code>null</code> if none.
357 *
358 * @see users.events.UserDataListener#userDeleted
359 *
360 * @override Never
361 */
362 public synchronized User deleteUser(String sName) {
363 User usrReturn = (User)m_mpUsers.remove(sName);
364
365 if (usrReturn != null) {
366 fireUserDeleted(usrReturn);
367 }
368
369 return usrReturn;
370 }
371
372 /**
373 * Add a UserDataListener. UserDataListeners will receive an event whenever a user
374 * was created or removed.
375 *
376 * @param udl the UserDataListener to add.
377 *
378 * @override Never
379 */
380 public void addUserDataListener(UserDataListener udl) {
381 m_lhListeners.add(UserDataListener.class, udl);
382 }
383
384 /**
385 * Remove a UserDataListener.
386 *
387 * @param udl the UserDataListener to remove.
388 *
389 * @override Never
390 */
391 public void removeUserDataListener(UserDataListener udl) {
392 m_lhListeners.remove(UserDataListener.class, udl);
393 }
394
395 /**
396 * Fire a <code>userAdded</code> event to all interested listeners.
397 *
398 * @param usr the user that was added.
399 *
400 * @override Never
401 */
402 protected void fireUserAdded(User usr) {
403 UserDataEvent ude = null;
404 // Guaranteed to return a non-null array
405 Object[] listeners = m_lhListeners.getListenerList();
406 // Process the listeners last to first, notifying
407 // those that are interested in this event
408 for (int i = listeners.length - 2; i >= 0; i -= 2) {
409 if (listeners[i] == UserDataListener.class) {
410 // Lazily create the event:
411 if (ude == null) {
412 ude = new UserDataEvent(this, usr);
413
414 }
415 ((UserDataListener)listeners[i + 1]).userAdded(ude);
416 }
417 }
418 }
419
420 /**
421 * Fire a <code>userDeleted</code> event to all interested listeners.
422 *
423 * @param usr the user that was deleted.
424 *
425 * @override Never
426 */
427 protected void fireUserDeleted(User usr) {
428 UserDataEvent ude = null;
429
430 // Guaranteed to return a non-null array
431 Object[] listeners = m_lhListeners.getListenerList();
432
433 // Process the listeners last to first, notifying
434 // those that are interested in this event
435 for (int i = listeners.length - 2; i >= 0; i -= 2) {
436 if (listeners[i] == UserDataListener.class) {
437 // Lazily create the event:
438 if (ude == null) {
439 ude = new UserDataEvent(this, usr);
440
441 }
442 ((UserDataListener)listeners[i + 1]).userDeleted(ude);
443 }
444 }
445 }
446
447 /**
448 * Associate a user with an object.
449 *
450 * <p>Only one user at a time can be associated with one Object. If there is already
451 * another user associated with the given Object, its association is undone and the
452 * user is returned.</p>
453 *
454 * <p>Only users that are actually managed by this UserManager can be logged in. An
455 * exception will be thrown if you try to log in a user that is unknown to this
456 * UserManager. Especially, this can happen if you try to log in a user that was
457 * previously removed using {@link #deleteUser}.</p>
458 *
459 * @param o the Object with which to associate the user.
460 * @param u the user to associate with the Object
461 *
462 * @return the user that was previously associated with the Object or
463 * <code>null</code> if none.
464 *
465 * @exception UnknownUserException if the user to log in is not known at this
466 * UserManager. A user is known at a UserManager, if the User object is registered,
467 * i.e. no <code>equals()</code> method of any kind is called.
468 *
469 * @see User#loggedOn
470 *
471 * @override Never
472 */
473 public synchronized User logOn(Object o, User u) {
474
475 User usrTemp = getUser(u.getName());
476
477 if ((usrTemp == null) || (usrTemp != u)) {
478 throw new UnknownUserException(u.getName());
479 }
480
481 User usrReturn = logOff(o);
482
483 if (u != null) {
484 m_mpCurrentUsers.put(o, u);
485
486 u.loggedOn(o);
487 }
488
489 return usrReturn;
490 }
491
492 /**
493 * Disassociate the current user from an Object.
494 *
495 * @param o the Object from which to disassociate a user.
496 *
497 * @return the user just logged off or <code>null</code> if none.
498 *
499 * @see User#loggedOff
500 *
501 * @override Never
502 */
503 public synchronized User logOff(Object o) {
504 User u = (User)m_mpCurrentUsers.remove(o);
505
506 if (u != null) {
507 u.loggedOff(o);
508 }
509
510 return u;
511 }
512
513 /**
514 * Retrieve the user currently associated with some Object.
515 *
516 * @param o the Object with which the searched user must be associated.
517 *
518 * @return the user associated with the given Object or <code>null</code> if none.
519 *
520 * @override Never
521 */
522 public synchronized User getCurrentUser(Object o) {
523 return (User)m_mpCurrentUsers.get(o);
524 }
525
526 ////////////////////////////////////////////////////////////////////////////////////////////
527 // STATIC PART
528 ////////////////////////////////////////////////////////////////////////////////////////////
529
530 /**
531 * The global UserManager.
532 */
533 private static UserManager s_umGlobal = new UserManager();
534
535 /**
536 * Get the global UserManager.
537 *
538 * <p>The global UserManager can be used as a centralized instance to manage all the
539 * users in an application.</p>
540 *
541 * @return the global UserManager.
542 */
543 public static synchronized UserManager getGlobalUM() {
544 return s_umGlobal;
545 }
546
547 /**
548 * Set a new UserManager to be the global UserManager from now on.
549 *
550 * @param umNew the new global UserManager.
551 *
552 * @return the previous UserManager.
553 */
554 public static synchronized UserManager setGlobalUM(UserManager umNew) {
555 UserManager umReturn = s_umGlobal;
556
557 s_umGlobal = umNew;
558
559 return s_umGlobal;
560 }
561 }