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