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 }