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    }