KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jcorporate > expresso > core > security > User


1 /* ====================================================================
2  * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
3  *
4  * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  *
18  * 3. The end-user documentation included with the redistribution,
19  * if any, must include the following acknowledgment:
20  * "This product includes software developed by Jcorporate Ltd.
21  * (http://www.jcorporate.com/)."
22  * Alternately, this acknowledgment may appear in the software itself,
23  * if and wherever such third-party acknowledgments normally appear.
24  *
25  * 4. "Jcorporate" and product names such as "Expresso" must
26  * not be used to endorse or promote products derived from this
27  * software without prior written permission. For written permission,
28  * please contact info@jcorporate.com.
29  *
30  * 5. Products derived from this software may not be called "Expresso",
31  * or other Jcorporate product names; nor may "Expresso" or other
32  * Jcorporate product names appear in their name, without prior
33  * written permission of Jcorporate Ltd.
34  *
35  * 6. No product derived from this software may compete in the same
36  * market space, i.e. framework, without prior written permission
37  * of Jcorporate Ltd. For written permission, please contact
38  * partners@jcorporate.com.
39  *
40  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
41  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
42  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
43  * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
44  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
46  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
47  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
48  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
50  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  * ====================================================================
53  *
54  * This software consists of voluntary contributions made by many
55  * individuals on behalf of the Jcorporate Ltd. Contributions back
56  * to the project(s) are encouraged when you make modifications.
57  * Please send them to support@jcorporate.com. For more information
58  * on Jcorporate Ltd. and its products, please see
59  * <http://www.jcorporate.com/>.
60  *
61  * Portions of this software are based upon other open source
62  * products and are subject to their respective licenses.
63  */

64
65 /*
66  * User.java
67  *
68  * Copyright 1999, 2000, 2001 Jcorporate Ltd.
69  */

70
71 package com.jcorporate.expresso.core.security;
72
73 import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
74 import com.jcorporate.expresso.core.controller.ControllerRequest;
75 import com.jcorporate.expresso.core.dataobjects.ContextNested;
76 import com.jcorporate.expresso.core.dataobjects.DataObject;
77 import com.jcorporate.expresso.core.dataobjects.Mappable;
78 import com.jcorporate.expresso.core.db.DBConnection;
79 import com.jcorporate.expresso.core.db.DBException;
80 import com.jcorporate.expresso.core.dbobj.LookupInterface;
81 import com.jcorporate.expresso.core.dbobj.SecuredDBObject;
82 import com.jcorporate.expresso.core.dbobj.ValidValue;
83 import com.jcorporate.expresso.core.logging.LogException;
84 import com.jcorporate.expresso.core.misc.Base64;
85 import com.jcorporate.expresso.core.misc.ByteArrayDataSource;
86 import com.jcorporate.expresso.core.misc.ConfigManager;
87 import com.jcorporate.expresso.core.misc.ConfigurationException;
88 import com.jcorporate.expresso.core.misc.EMailSender;
89 import com.jcorporate.expresso.core.misc.EventHandler;
90 import com.jcorporate.expresso.core.misc.StringUtil;
91 import com.jcorporate.expresso.kernel.util.FastStringBuffer;
92 import com.jcorporate.expresso.services.dbobj.UserGroup;
93 import org.apache.log4j.Logger;
94
95 import java.util.ArrayList JavaDoc;
96 import java.util.Enumeration JavaDoc;
97 import java.util.Hashtable JavaDoc;
98 import java.util.Iterator JavaDoc;
99 import java.util.List JavaDoc;
100 import java.util.Vector JavaDoc;
101
102
103 /**
104  * This class provides a front-end for maintaining Expresso
105  * Users. This class provides an abstraction of the minimum
106  * information required for a valid User in Expresso. This
107  * class is an "Adaptor" that "adapts" the actual class that
108  * implements the User object. "Adaptee" user classes must
109  * implement the UserInfo interface. In addition, classes that
110  * implement the UserListener interface can listen in on when
111  * user objects are added, modified or deleted.
112  *
113  * @author Michael Nash
114  * @see com.jcorporate.expresso.core.security.UserInfo interface
115  * @see com.jcorporate.expresso.core.security.UserListener interface
116  * @see com.jcorporate.expresso.core.dbobj.LookupInterface
117  */

118 public class User
119         implements LookupInterface, Mappable, ContextNested {
120
121     // Name of this class, for log/debug purposes
122
private static final String JavaDoc thisClass = User.class.getName();
123
124     // The actual UserInfo class the implements the "meat" of this User
125
private UserInfo myUserInfo = null;
126
127     /**
128      *
129      */

130     protected static UserInfo notLoggedInUser = null;
131
132     // The DB context that this User resides in
133
private String JavaDoc dbName = "default";
134
135     /**
136      * The log4j logger.
137      */

138     private static Logger log = Logger.getLogger(User.class);
139
140     /**
141      * hash of classes which have registered to listen for CRUD notifications
142      */

143     private static ConcurrentReaderHashMap listeners = null;
144
145     /**
146      * the anonymous user; used in systems where anonymous guest
147      * are allowed; different than UNKNOWN because there is some kind
148      * of status/login conferred by system; user id = 1 usually
149      */

150     public static final String JavaDoc ANONYMOUS_ALLOWED_GUEST_USER = "Anonymous";
151
152     /**
153      * the unknown user; no login yet; user id = 2 usually
154      */

155     public static final String JavaDoc UNKNOWN_USER = "NONE";
156
157     /**
158      * the admin user; user id = 3 usually
159      */

160     public static final String JavaDoc ADMIN_USER = "Admin";
161
162     /**
163      * the string code for an active account
164      *
165      * @see #setAccountStatus
166      */

167     public static final String JavaDoc ACTIVE_ACCOUNT_STATUS = "A";
168
169     /**
170      * the string code for an disabled account
171      *
172      * @see #setAccountStatus
173      */

174     public static final String JavaDoc DISABLED_ACCOUNT_STATUS = "D";
175
176     /**
177      * the string code for an disabled account
178      *
179      * @see #setAccountStatus
180      */

181     public static final String JavaDoc INACTIVE_ACCOUNT_STATUS = "I";
182
183
184     /**
185      * the string code for an account that is awaiting admin approval after registration
186      *
187      * @see #setAccountStatus
188      */

189     public static final String JavaDoc WAITING_FOR_APPROVAL_ACCOUNT_STATUS = "W";
190
191
192     /**
193      * Default constructor
194      */

195     public User() {
196     } /* User() */
197
198
199     /**
200      * Constructs a user with a particular user info. Useful for defining
201      * some special case users where we don't want database access. See
202      * {@link com.jcorporate.expresso.core.security.SuperUser} for example usage.
203      *
204      * @param uInfo UserInfo
205      */

206     public User(UserInfo uInfo) {
207         myUserInfo = uInfo;
208     }
209
210
211     /**
212      * Adds this user to the underlying storage mechanism (SQL-DB, LDAP, etc.)
213      *
214      * @throws DBException If the add fails
215      */

216     public void add()
217             throws DBException {
218
219         // If a User is added without a status, we set the AccountStatus
220
// to "I" for security reasons
221
if ("".equals(getAccountStatus())) {
222             setAccountStatus("I");
223         }
224
225         // Let the actual implementation add the user
226
getUserInfo().add();
227         //the underlying object must perform the notification upon success
228
//of the operation.
229
// addNotify(this.myUserInfo);
230
} /* add() */
231
232     /**
233      * Used when a UserInfo Object adds itself outside of the 'User' class.
234      *
235      * @param uif a user info object that has been modified.
236      * @throws DBException if ther's an error performing the 'add' operation
237      */

238     public void addNotify(UserInfo uif) throws DBException {
239         this.myUserInfo = uif;
240
241         // Any classes that implement the UserListener interface
242
// and then call User.addListener() to register will
243
// be called back when a new User is added
244

245         if (listeners != null) {
246             ArrayList JavaDoc theListeners = null;
247             synchronized (listeners) {
248                 theListeners = new ArrayList JavaDoc(listeners.values());
249             }
250
251             for (Iterator JavaDoc iterator = theListeners.iterator(); iterator.hasNext();) {
252                 UserListener listener = (UserListener) iterator.next();
253                 listener.addedUser(this);
254             }
255         }
256     }
257
258
259     /**
260      * Adds a UserListener object to list of listeners.
261      * The listener param is passed in as an instance, but this is a STATIC LISTENER scheme.
262      * In other words, one instance is not listening to another instance. The *classes*
263      * are listening to one another. It is generally used as a kind of a poor substitute for 'detail' records,
264      * which are deleted in a cascading manner. So when the User object is add/modified/deleted, it will
265      * call the method on the provided instance, which usually causes a search and manipulation of
266      * all records having to do with the user--not that each record has been registered as listening.
267      *
268      * @param listener UserListener The object whose object TYPE wants to listen in on User add/modify/delete; we will keep this instance for listening, but any other object of this type cannot register for listening--it is just a representative instance, and the hash is on class name
269      * @see com.jcorporate.expresso.services.dbobj.RegistrationDBObject for an example of a listener (it is superclass to several listeners)
270      */

271     public static synchronized void addListener(UserListener listener) {
272         if (listeners == null) {
273             listeners = new ConcurrentReaderHashMap();
274         }
275
276         listeners.put(listener.getClass().getName(), listener);
277     } /* addListener(UserListener) */
278
279     /**
280      * Determines if this dbobject is already a listener.
281      *
282      * @param listener The UserListener class
283      * @return boolean <b>true</b> if the class is already registered as a listener
284      */

285     public static synchronized boolean isListener(UserListener listener) {
286         if (listeners == null) {
287             return false;
288         }
289
290         return listeners.get(listener.getClass().getName()) != null;
291     }
292
293
294     /**
295      * This method just checks to make sure that the submitted emailAuthCode
296      * matches the real code.
297      * Creation date: (8/8/00 3:08:49 PM)
298      * author: Adam Rossi, PlatinumSolutions, Inc.
299      *
300      * @param emailAuthCode java.lang.String
301      * @return boolean
302      * @throws com.jcorporate.expresso.core.db.DBException
303      * The exception description.
304      */

305     public boolean checkEmailAuthCode(String JavaDoc emailAuthCode)
306             throws DBException {
307         try {
308             String JavaDoc realEmailAuthCode = "";
309             realEmailAuthCode = getEmailAuthCode();
310
311             if (realEmailAuthCode == null) {
312                 realEmailAuthCode = "";
313             }
314             if (realEmailAuthCode.equals(emailAuthCode)) {
315                 return true;
316             } else {
317                 return false;
318             }
319         } catch (Exception JavaDoc e) {
320             throw new DBException("Error in checking Email Auth Code: " +
321                     e.toString());
322         }
323     } /* checkEmailAuthCode(String) */
324
325
326     /**
327      * Uncaches the underlying UserInfo implementation object
328      *
329      * @throws com.jcorporate.expresso.core.db.DBException
330      * The exception description.
331      */

332     public synchronized void clear()
333             throws DBException {
334         myUserInfo = null;
335     } /* clear() */
336
337
338     /**
339      * Calls back registered listeners so they can cleanup
340      * and then deletes the user
341      *
342      * @throws DBException If the delete fails
343      */

344     public void delete()
345             throws DBException {
346
347 // deleteNotify(this.myUserInfo);
348
//the underlying object must perform the notification upon success
349
//of the operation.
350

351         // Delete the user
352
getUserInfo().delete();
353     } /* delete() */
354
355     /**
356      * Used for when a UserInfo implementation deletes itself outside of the
357      * User Interface
358      *
359      * @param uif The user info that has been modified.
360      */

361     public void deleteNotify(UserInfo uif) throws DBException {
362         //
363
//This must be kept since it is possible that it was
364
//getting modified outside the User object
365
//
366
//
367
this.myUserInfo = uif;
368
369         // Any classes that implement the UserListener interface
370
// and then call User.addListener() to register will
371
// be called back right before a User is deleted
372

373         if (listeners != null) {
374             ArrayList JavaDoc theListeners = null;
375             synchronized (listeners) {
376                 theListeners = new ArrayList JavaDoc(listeners.values());
377             }
378
379             for (Iterator JavaDoc iterator = theListeners.iterator(); iterator.hasNext();) {
380                 UserListener listener = (UserListener) iterator.next();
381                 listener.deletedUser(this);
382             }
383         }
384     }
385
386
387     /**
388      * Find a user matching the values of the properties that have been set
389      *
390      * @return true if user is found
391      * @throws DBException Thrown if the underlying implementation throws an exception
392      */

393     public boolean find()
394             throws DBException {
395         return getUserInfo().find();
396     } /* find() */
397
398
399     /**
400      * Returns the current status of the account. Possible states are
401      * active, disabled, inactive.
402      *
403      * @return java.lang.String
404      * @throws DBException If the underlying User implementation throws the same
405      */

406     public String JavaDoc getAccountStatus()
407             throws DBException {
408         return getUserInfo().getAccountStatus();
409     } /* getAccountStatus(String) */
410
411
412     /**
413      * Returns a list of all the Users in the database. The returned Vector contains
414      * UserInfo objects.
415      *
416      * @return java.util.Vector
417      * @throws DBException If the underlying User implementation throws the same
418      */

419     public Vector JavaDoc getAllUsers()
420             throws DBException {
421         return getUserInfo().getAllUsers();
422     } /* getAllUsers() */
423
424
425     /**
426      * Returns the currently set DB context
427      *
428      * @return java.util.String
429      */

430     public String JavaDoc getDataContext() {
431         return dbName;
432     } /* getDBName() */
433
434     /**
435      * Returns the email address of the user
436      *
437      * @return java.lang.String
438      * @throws com.jcorporate.expresso.core.db.DBException
439      * If the underlying User implementation throws the same
440      */

441     public String JavaDoc getEmail()
442             throws DBException {
443         return getUserInfo().getEmail();
444     } /* getEmail() */
445
446
447     /**
448      * Here we generate an authorization code that would be hard for someone to
449      * guess. The idea is that the person has to check the email sent to them to
450      * get this number, and then click on the specially encoded URL to ensure
451      * that he/she actually is checking the email account used at registration.
452      * <p/>
453      * The little trick of getting the time in milliseconds that the person
454      * registered, multiplying by some constant, and then rounding, is extremely
455      * weak. We need a better method of generating a unique code that will
456      * "play nice" in a query string.
457      * <p/>
458      * Creation date: (8/8/00 3:00:41 PM)
459      * author: Adam Rossi, PlatinumSolutions, Inc.
460      *
461      * @return java.lang.String
462      */

463     public String JavaDoc getEmailAuthCode()
464             throws DBException {
465         return getUserInfo().getEmailAuthCode();
466     } /* getEmailAuthCode() */
467
468
469     /**
470      * Returns the code required for authorization via email
471      *
472      * @return java.lang.String
473      * @throws DBException If the underlying User implementation throws the same
474      */

475     public String JavaDoc getEmailValCode()
476             throws DBException {
477         return getUserInfo().getEmailValCode();
478     } /* getEmailValCode() */
479
480
481     /**
482      * Return a vector of the group names that this user belongs to
483      *
484      * @return Vector Group names that this user belongs to
485      * @throws DBException If an error occurs when the group info is read
486      */

487     public Vector JavaDoc getGroups()
488             throws DBException {
489         UserInfo myInfo = getUserInfo();
490         return myInfo.getGroups();
491     } /* getGroups() */
492
493
494     /**
495      * Return a List of the group names that this user belongs to
496      *
497      * @return Vector Group names that this user belongs to
498      * @throws DBException If an error occurs when the group info is read
499      * @todo Modify userInfo so that getGroupsList() is implemented so we
500      * can deprecate getGroups();
501      */

502     public List JavaDoc getGroupsList()
503             throws DBException {
504         UserInfo myInfo = getUserInfo();
505
506         return new ArrayList JavaDoc(myInfo.getGroups());
507     }
508
509     /**
510      * Returns the string that the user needs to use to login.
511      *
512      * @return java.lang.String
513      * @throws DBException If the underlying User implementation throws the same
514      */

515     public String JavaDoc getLoginName()
516             throws DBException {
517         return getUserInfo().getLoginName();
518     } /* getLoginName() */
519
520
521     /**
522      * Returns the password string for the user. NOTE: The user class itself has no idea whether the
523      * password was encoded or not, that will be upto the implementation of whatever
524      * servlet/controller that sets the password in the first place. Conversely, the servlet/controller
525      * that logs the user in must know whether the password that this method retrieves was encoded or
526      * not.
527      *
528      * @return java.lang.String
529      * @throws DBException If the underlying User implementation throws the same
530      */

531     public String JavaDoc getPassword()
532             throws DBException {
533         return getUserInfo().getPassword();
534     } /* getPassword() */
535
536
537     /**
538      * Returns the static constant notLogged in user.
539      *
540      * @return An instantiated UserInfo object
541      */

542     public synchronized UserInfo getNotLoggedInUser() throws DBException {
543         if (notLoggedInUser == null) {
544             notLoggedInUser = constructNotLoggedInUser();
545         }
546
547         return notLoggedInUser;
548     }
549
550     /**
551      * @return the 'not logged in user'
552      */

553     protected UserInfo constructNotLoggedInUser() throws DBException {
554         UserInfo ui = this.getUserInfo();
555         ui.setLoginName(UNKNOWN_USER);
556         ui.find();
557
558         return ui;
559     }
560
561     /**
562      * Whether registration has been completed beyond the basic user info
563      *
564      * @return java.lang.String
565      * @throws DBException If the underlying UserInfo implementation throws the same
566      */

567     public boolean getRegComplete()
568             throws DBException {
569         return getUserInfo().getRegComplete();
570     } /* getRegComplete()*/
571
572
573     /**
574      * Returns the unique integer for the registration domain that this user belongs to
575      *
576      * @return java.lang.String
577      * @throws com.jcorporate.expresso.core.db.DBException
578      * If the underlying User implementation throws the same
579      */

580     public String JavaDoc getRegistrationDomain()
581             throws DBException {
582         return getUserInfo().getRegistrationDomain();
583     } /* getRegistrationDomainId() */
584
585
586     /**
587      * Returns the unique integer used as a key to identify the user
588      *
589      * @return java.lang.String
590      * @throws com.jcorporate.expresso.core.db.DBException
591      * If the underlying User implementation throws the same
592      */

593     public String JavaDoc getUidString()
594             throws DBException {
595         return Integer.toString(getUserInfo().getUid());
596     } /* getUidString() */
597
598
599     public int getUid()
600             throws DBException {
601         return getUserInfo().getUid();
602     }
603
604     /**
605      * Return the UserInfo object Normally you would not use this directly, except
606      * in special cases where you need to get to the UserInfo object.
607      *
608      * @return the UserInfo object
609      * @throws DBException If an error occurs when setting dbname in a newly created UserInfo object
610      */

611     public UserInfo getUserInfo()
612             throws DBException {
613
614         if (myUserInfo != null) {
615             return myUserInfo;
616         }
617
618         String JavaDoc infoClass = StringUtil.notNull(ConfigManager.getClassHandler("userInfo"));
619
620         if (infoClass.equals("")) {
621             infoClass = com.jcorporate.expresso.services.dbobj.DefaultUserInfo.class.getName();
622         }
623         try {
624             Object JavaDoc o = Class.forName(infoClass).newInstance();
625
626             if (!(o instanceof UserInfo)) {
627                 throw new DBException(thisClass + "getUserInfo()" + ":The class " + infoClass +
628                         " is not a UserInfo object - it's a " +
629                         o.getClass().getName());
630             }
631
632             myUserInfo = (UserInfo) o;
633         } catch (ClassNotFoundException JavaDoc ce) {
634             throw new DBException(thisClass + "getUserInfo()" + ":Class not found '" + infoClass,
635                     ce);
636         } catch (InstantiationException JavaDoc ie) {
637             throw new DBException(thisClass + "getUserInfo()" + ":Error instantiating class '" +
638                     infoClass, ie);
639         } catch (IllegalAccessException JavaDoc iae) {
640             throw new DBException(thisClass + "getUserInfo()" + ":Illegal access error " +
641                     "instantiating class '" + infoClass, iae);
642         }
643
644         myUserInfo.setDBName(this.getDataContext());
645
646         return myUserInfo;
647     } /* getUserInfo() */
648
649     /**
650      * Returns a descriptiptive, longer name for the user
651      * this is NOT THE UNIQUE LOGIN NAME.
652      *
653      * @return java.lang.String
654      * @throws DBException If the underlying User implementation throws the same
655      * @see #getLoginName()
656      */

657     public String JavaDoc getDisplayName()
658             throws DBException {
659         return getUserInfo().getUserName();
660     } /* getUserName() */
661
662
663     /**
664      * Returns the possible values for the multivalued properties
665      *
666      * @param fieldName The fieldname to get the valid values for
667      * @return java.util.Vector
668      * @throws DBException The exception description.
669      */

670     public synchronized Vector JavaDoc getValidValues(String JavaDoc fieldName)
671             throws DBException {
672
673         if ("AccountStatus".equals(fieldName)) {
674             Vector JavaDoc values = new Vector JavaDoc();
675             values.addElement(new ValidValue("A", "Active"));
676             values.addElement(new ValidValue("I",
677                     "Inactive Until Email Confirmation"));
678             values.addElement(new ValidValue("D", "Disabled"));
679             values.addElement(new ValidValue("W", "Waiting For Approval"));
680             values.addElement(new ValidValue("X",
681                     "Registration Denied By Administrator"));
682
683             return values;
684         }
685
686         return null;
687     } /* getValidValues(String) */
688
689
690     public Vector JavaDoc getValues()
691             throws com.jcorporate.expresso.core.db.DBException {
692         return getUserInfo().getValues();
693     }
694
695     /**
696      * hashEncodePassword: If passed a plaintext string > 0 bytes, then this
697      * function will hash the password, then Base64 encode it and return it
698      * as a string.
699      * <p/>
700      * If the password is zero length, then it will simply return a zero length
701      * string also.
702      *
703      * @param plaintext - the password to process in this manner: <br>
704      * returnValue = Base64(SHA-1(plaintext))
705      * @return a String representing the password hashencoded
706      */

707     private String JavaDoc hashEncodePassword(String JavaDoc plaintext)
708             throws DBException {
709         if (plaintext == null) {
710             throw new DBException(thisClass + "hashEncodePassword()" + ": Password Must not be NULL");
711         }
712         if (plaintext.length() == 0) {
713             return plaintext;
714         }
715         try {
716             return Base64.encode(CryptoManager.getInstance().getStringHash().produceHash(plaintext.getBytes()));
717         } catch (Exception JavaDoc ex) {
718             throw new DBException(thisClass + "hashEncodePassword()" + ":Error hashing Password:" +
719                     " You may not have installed the" +
720                     " Cryptography Extensions Properly:", ex);
721         }
722     } /* hashEncodePassword(String) */
723
724
725     /**
726      * Send this user a notification via e-mail.
727      *
728      * @param subject Subject of the e-mail
729      * @param message Message to send in body of e-mail
730      * @throws DBException If the mail message cannot be sent
731      */

732     public void notify(String JavaDoc subject, String JavaDoc message)
733             throws DBException {
734         notify(subject, message, false);
735     } /* notify(String, String) */
736
737     /**
738      * Notify the user with the optional parameter of using html format
739      *
740      * @param subject the message subject
741      * @param message the message, possibly in html format
742      * @param htmlFormat true if you want the message to be html formatted.
743      * @throws DBException upon error
744      */

745     public void notify(String JavaDoc subject, String JavaDoc message, boolean htmlFormat)
746             throws DBException {
747         notify(subject, message, htmlFormat, null);
748     }
749
750     /**
751      * Notify the user with the optional parameter of using html
752      * format with virtual raw data attachments.
753      *
754      * @param subject the message subject
755      * @param message the message, possibly in html format
756      * @param htmlFormat true if you want the message to be html formatted.
757      * @param attachments an primitive array of raw data byte array data sources.
758      * @throws DBException upon error from database
759      * @see com.jcorporate.expresso.core.misc.ByteArrayDataSource
760      */

761     public void notify(String JavaDoc subject, String JavaDoc message, boolean htmlFormat,
762                        ByteArrayDataSource attachments[])
763             throws DBException {
764
765         if (log.isDebugEnabled()) {
766             log.debug("Notifying user " + getUserInfo().getLoginName()
767                     + " of " + subject);
768         }
769
770         String JavaDoc sendToUser = getUserInfo().getEmail();
771
772         try {
773             EMailSender ems = new EMailSender();
774             ems.setDBName(this.getDataContext());
775             if (htmlFormat) {
776                 ems.setEmailHtmlFormat();
777             }
778
779             if (attachments != null) {
780                 // Register virtual raw data attachments
781
for (int k = 0; k < attachments.length; ++k) {
782                     ems.addDataSourceAttachment(attachments[k]);
783                 }
784             }
785
786             ems.send(sendToUser, subject, message);
787         } catch (Exception JavaDoc e) {
788             throw new DBException(thisClass + "notify()" +
789                     ":Uncaught exception sending e-mail", e);
790         }
791     } /* notify(String, String) */
792
793
794     /**
795      * Check if the given number is in the range of letters and
796      * digits that we want to use for generating a password
797      * Previously in com.jcorporate.expresso.ext.servlet.RegisterUser.java
798      *
799      * @param x The random number to check against
800      * @return true if the paramter is a printable character
801      */

802     private boolean okNumber(double x) {
803         int oneNumber = new Double JavaDoc(x).intValue();
804
805         if ((oneNumber >= 65) && (oneNumber <= 90)) {
806             return true;
807         }
808         if ((oneNumber >= 48) && (oneNumber <= 57)) {
809             return true;
810         }
811         if ((oneNumber >= 97) && (oneNumber <= 122)) {
812             return true;
813         }
814
815         return false;
816     } /* okNumber(double) */
817
818     /**
819      * passwordEquals - feed it a password and it will tell you if the hash of it
820      * matches the one on file.
821      *
822      * @param tryPassword The value the user input for an attempted login.
823      * @return boolean
824      */

825     public boolean passwordEquals(String JavaDoc tryPassword)
826             throws DBException {
827         if (tryPassword == null) {
828             throw new DBException(thisClass + ":tryPassword Must not be NULL");
829         }
830
831         return getUserInfo().passwordEquals(tryPassword);
832     } /* passwordEquals(String) */
833
834
835     /**
836      * Called by the various objects that can log in a user
837      * to do post-login tasks
838      */

839     public void postLogin()
840             throws DBException, LogException {
841         UserInfo myInfo = getUserInfo();
842         UserGroup oneGroup = new UserGroup(SecuredDBObject.SYSTEM_ACCOUNT);
843         oneGroup.setDataContext(getDataContext());
844
845         String JavaDoc theEvent = null;
846         Hashtable JavaDoc allEvents = new Hashtable JavaDoc(1);
847         String JavaDoc oneGroupName = null;
848
849         for (Enumeration JavaDoc gl = getGroups().elements(); gl.hasMoreElements();) {
850             oneGroupName = (String JavaDoc) gl.nextElement();
851             oneGroup.clear();
852             oneGroup.setField("GroupName", oneGroupName);
853
854             if (oneGroup.find()) {
855                 theEvent = oneGroup.getField("LoginEvent");
856
857                 if (!theEvent.equals("")) {
858                     allEvents.put(theEvent, oneGroup.getField("GroupName"));
859                 }
860             } /* if the group exists */
861
862         } /* for each group user is a member of */
863
864
865         /* if any events need to be triggered... */
866         String JavaDoc theMessage = null;
867
868         if (allEvents.size() > 0) {
869             for (Enumeration JavaDoc el = allEvents.keys(); el.hasMoreElements();) {
870                 theEvent = (String JavaDoc) el.nextElement();
871                 theMessage = "User " + myInfo.getLoginName() +
872                         " (" + myInfo.getUserName() +
873                         ") who is a member " + " of group " +
874                         (String JavaDoc) allEvents.get(theEvent) +
875                         " has just logged in.";
876                 EventHandler.Event(getDataContext(), theEvent, theMessage, true);
877             } /* for each event */
878
879         } /* if any events to be triggered */
880
881     } /* postLogin() */
882
883
884     /**
885      * Generates a random plaintext password
886      *
887      * @return java.lang.String
888      */

889     public String JavaDoc randomPassword() {
890         int passwordLength;
891         double oneNumber = 0;
892         char oneChar;
893         int iterations = 0;
894
895         //
896
//Read the property value of minimum password length
897
//
898
String JavaDoc propValue = "";
899
900         try {
901             StringUtil.notNull(ConfigManager.getContext(getDataContext()).getMinPasswordSize());
902         } catch (ConfigurationException ce) {
903             propValue = "";
904         }
905         if (!propValue.equals("")) {
906             try {
907                 passwordLength = Integer.parseInt(propValue, 10);
908             } catch (NumberFormatException JavaDoc ex) {
909
910                 //Bad number
911
passwordLength = 6;
912             }
913         } else {
914             passwordLength = 6;
915         }
916
917         FastStringBuffer newPassword = new FastStringBuffer(passwordLength);
918         /////////////////////////////////
919
//
920
//Now Generate the new password. (Code from servlet.RegisterUser) before)
921
//
922
while ((newPassword.length() < passwordLength) && (iterations < 200)) {
923             iterations++;
924             oneNumber = Math.random() * 100;
925
926             if (okNumber(oneNumber)) {
927                 oneChar = (char) new Double JavaDoc(oneNumber).intValue();
928                 newPassword.append(oneChar);
929             }
930         }
931
932         return newPassword.toString();
933     } /* randomPassword() */
934
935     /**
936      * @throws com.jcorporate.expresso.core.db.DBException
937      * The exception description.
938      */

939     public void retrieve()
940             throws DBException {
941         getUserInfo().retrieve();
942     } /* retrieve() */
943
944
945     /**
946      * @throws DBException
947      */

948     public void sendAuthEmail()
949             throws DBException {
950         getUserInfo().sendAuthEmail();
951     } /* sendAuthEmail() */
952
953
954     /**
955      * Send this user an e-mail with file attachments.
956      *
957      * @param subject Subject of the e-mail
958      * @param message Message to send in body of e-mail
959      * @param fileNames of the files to attach
960      * @throws DBException If the mail message cannot be sent
961      */

962     public void sendFileTo(String JavaDoc subject, String JavaDoc message, Vector JavaDoc fileNames)
963             throws DBException, LogException {
964         UserInfo myInfo = getUserInfo();
965         log.debug("Sending " + fileNames.size() + " files via e-mail to " +
966                 myInfo.getLoginName());
967
968         String JavaDoc sendToUser = getUserInfo().getEmail();
969
970         try { // create some properties and get the default Session
971
EMailSender ems = new EMailSender();
972             ems.setDBName(getDataContext());
973             ems.addFileAttachments(fileNames);
974             ems.send(sendToUser, subject, message);
975         } catch (Exception JavaDoc e) {
976             throw new DBException(thisClass + "sendFileTo" + ":Error sending e-mail", e);
977         }
978     } /* sendFileTo(String, String, Vector) */
979
980
981     /**
982      * @throws DBException
983      */

984     public void sendFollowUpEmail()
985             throws DBException {
986         getUserInfo().sendFollowUpEmail();
987     } /* sendFollowUpEmail() */
988
989
990     /**
991      * Sets the current status of the account
992      *
993      * @param accountStatus java.lang.String One of the values "A" (active), "I" (inactive), "D" (disabled)
994      * @throws DBException If the underlying UserInfo implementation throws the same
995      */

996     public void setAccountStatus(String JavaDoc accountStatus)
997             throws DBException {
998         getUserInfo().setAccountStatus(accountStatus);
999     } /* setAccountStatus(String) */
1000
1001
1002    /**
1003     * Switches data contexts for the User Object
1004     *
1005     * @param newDBName The new data context to use this security object for
1006     * @throws com.jcorporate.expresso.core.db.DBException
1007     * The exception description.
1008     */

1009    public synchronized void setDBName(String JavaDoc newDBName)
1010            throws DBException {
1011        dbName = newDBName;
1012        getUserInfo().setDBName(newDBName);
1013    } /* setDBName(String) */
1014
1015
1016    /**
1017     * Sets the email address for the user
1018     *
1019     * @param email the new email address of this user
1020     * @throws com.jcorporate.expresso.core.db.DBException
1021     * If the underlying User implementation throws the same
1022     */

1023    public void setEmail(String JavaDoc email)
1024            throws DBException {
1025        getUserInfo().setEmail(email);
1026    } /* setEmail(String) */
1027
1028
1029    /**
1030     * Sets the validation code for authorization via email
1031     *
1032     * @param code the new validation code
1033     */

1034    public void setEmailValCode(String JavaDoc code)
1035            throws DBException {
1036        getUserInfo().setEmailValCode(code);
1037    } /* setEmailValCode(String) */
1038
1039    /**
1040     * Sets the name to be used by this user to login
1041     *
1042     * @param loginName the new login name for this user object
1043     * @throws com.jcorporate.expresso.core.db.DBException
1044     * If the underlying User implementation throws the same
1045     */

1046    public void setLoginName(String JavaDoc loginName)
1047            throws DBException {
1048        getUserInfo().setLoginName(loginName);
1049    } /* setLoginName(String) */
1050
1051
1052    /**
1053     * Sets the password to be used by the user. The password is expected to be plaintext
1054     *
1055     * @param password the new password to set for this user
1056     * @throws com.jcorporate.expresso.core.db.DBException
1057     * If the underlying User implementation throws the same
1058     */

1059    public void setPassword(String JavaDoc password)
1060            throws DBException {
1061// getUserInfo().setPassword(hashEncodePassword(password));
1062
getUserInfo().setPassword(getUserInfo().hashEncodePassword(password));
1063    } /* setPassword(String) */
1064
1065    /**
1066     * Sets the status of whether the extended registration has been completed or not
1067     *
1068     * @param status java.lang.String Valid values are "Y" or "N"
1069     * @throws DBException If the underlying UserInfo implementation throws the same
1070     */

1071    public void setRegComplete(boolean status)
1072            throws DBException {
1073        getUserInfo().setRegComplete(status);
1074    } /* setRegComplete(boolean) */
1075
1076
1077    /**
1078     * Sets the registration domain that this user belongs to
1079     *
1080     * @param domain The registration domain that this user belongs to.
1081     * @throws com.jcorporate.expresso.core.db.DBException
1082     * If the underlying User implementation throws the same
1083     */

1084    public void setRegistrationDomain(String JavaDoc domain)
1085            throws DBException {
1086        getUserInfo().setRegistrationDomain(domain);
1087    } /* setRegistrationDomainId() */
1088
1089
1090    /**
1091     * Sets the uid, used for finding...
1092     *
1093     * @param uid The new UID integer to set this user object to.
1094     * @throws com.jcorporate.expresso.core.db.DBException
1095     * If the underlying User implementation throws the same
1096     */

1097    public void setUid(int uid)
1098            throws DBException {
1099        getUserInfo().setUid(uid);
1100    } /* setUid(String) */
1101
1102
1103    /**
1104     * Sets the user id. Parsing the string to an integer
1105     *
1106     * @param uid a string containing an integer value
1107     * @throws DBException upon parse error
1108     */

1109    public void setUid(String JavaDoc uid)
1110            throws DBException {
1111        try {
1112            int uidAsInt = new Integer JavaDoc(uid).intValue();
1113            getUserInfo().setUid(uidAsInt);
1114        } catch (NumberFormatException JavaDoc ne) {
1115            throw new DBException(ne);
1116        }
1117    }
1118
1119    /**
1120     * Sets a long, descriptive name for the user
1121     *
1122     * @param name the new 'full name' of the user
1123     * @throws com.jcorporate.expresso.core.db.DBException
1124     * If the underlying User implementation throws the same
1125     */

1126    public void setDisplayName(String JavaDoc name)
1127            throws DBException {
1128        getUserInfo().setUserName(name);
1129    } /* setUserName(String) */
1130
1131
1132    /**
1133     * This method is called to update the properties of an User object.
1134     * All changed and unchanged fields must have their values filled in
1135     * The best way is to do a find() on the User first, and then to set
1136     * the modified fields before calling this method.
1137     *
1138     * @throws com.jcorporate.expresso.core.db.DBException
1139     * The exception description.
1140     */

1141    public void update()
1142            throws DBException {
1143
1144        // Update the user's info
1145
getUserInfo().update();
1146
1147        //the underlying object must perform the notification upon success
1148
//of the operation.
1149
// updateNotify(this.myUserInfo);
1150
} /* update() */
1151
1152    /**
1153     * Used to notify UserListeners that a UserInfo object has modified
1154     * itself outside of the User object.
1155     *
1156     * @param uif The new user info to update
1157     */

1158    public void updateNotify(UserInfo uif) throws DBException {
1159        //
1160
//This must be kept since it is possible that it was
1161
//getting modified outside the User object
1162
//
1163
//
1164
this.myUserInfo = uif;
1165
1166        // Any classes that implement the UserListener interface
1167
// and then call User.addListener() to register will
1168
// be called back right before a User is deleted
1169
if (listeners != null) {
1170            ArrayList JavaDoc theListeners = null;
1171            synchronized (listeners) {
1172                theListeners = new ArrayList JavaDoc(listeners.values());
1173            }
1174
1175            for (Iterator JavaDoc iterator = theListeners.iterator(); iterator.hasNext();) {
1176                UserListener listener = (UserListener) iterator.next();
1177                listener.modifiedUser(this);
1178            }
1179        }
1180    }
1181
1182    /**
1183     * is set first time that isAdmin() is run
1184     */

1185    private static Integer JavaDoc ADMIN_ID = null;
1186
1187    /**
1188     * determine if this user is admin
1189     *
1190     * @return true if this user is the Administrator account
1191     */

1192    public boolean isAdmin() throws DBException {
1193        if (ADMIN_ID == null) {
1194            int id = getIdFromLogin(ADMIN_USER, getDataContext());
1195            ADMIN_ID = new Integer JavaDoc(id);
1196        }
1197
1198        return ADMIN_ID.intValue() == this.getUid();
1199    }
1200
1201    /**
1202     * determine if this user is admin
1203     * WARNING: assumes dbname = 'default'
1204     *
1205     * @param id of user
1206     * @return true if the id is an Admin user.
1207     * @throws DBException upon error
1208     */

1209    public static boolean isAdmin(int id) throws DBException {
1210        User user = new User();
1211        user.setUid(id);
1212        return user.isAdmin();
1213    }
1214
1215    /**
1216     * determine admin id (usually '3')
1217     * WARNING: assumes dbname = 'default'
1218     *
1219     * @return the uid of user "Admin"
1220     * @throws DBException upon error
1221     */

1222    public static int getAdminId() throws DBException {
1223        return getAdminId(DBConnection.DEFAULT_DB_CONTEXT_NAME);
1224    }
1225
1226    /**
1227     * Retrieves the User instance of the current user.
1228     *
1229     * @param dbName String the data context to check.
1230     * @return User a User instance.
1231     * @throws DBException if there was no admin user found or
1232     * other database errors.
1233     */

1234    public static User getAdmin(String JavaDoc dbName) throws DBException {
1235        User user = new User();
1236        user.setDataContext(dbName);
1237        user.setLoginName(ADMIN_USER);
1238        if (!user.find()) {
1239            throw new DBException("Unable to locate: " + ADMIN_USER);
1240        }
1241
1242        return user;
1243    }
1244
1245    /**
1246     * determine admin id (usually '3')
1247     *
1248     * @param dbname the Database context to use
1249     * @return the id of the admin
1250     * @throws DBException upon error
1251     */

1252    public static int getAdminId(String JavaDoc dbname) throws DBException {
1253        User user = new User();
1254        user.setDataContext(dbname);
1255        user.isAdmin(); // make sure first test is done
1256
return ADMIN_ID.intValue();
1257    }
1258
1259    /**
1260     * determine if this user is admin
1261     *
1262     * @param name the login name to test
1263     * @return true if the name is the Admin user.
1264     */

1265    public static boolean isAdmin(String JavaDoc name) {
1266        return ADMIN_USER.equals(name);
1267    }
1268
1269    /**
1270     * determine if this user is unknown
1271     *
1272     * @param name the login name of the user
1273     * @return true if the name is UNKNOWN_USER ("NONE")
1274     */

1275    public static boolean isUnknownUser(String JavaDoc name) {
1276        return UNKNOWN_USER.equals(name);
1277    }
1278
1279    /**
1280     * the primary group of this user is appropriate for unix-like purposes,
1281     * such as setting the group for a file permission
1282     *
1283     * @return name of the primary group of this user; null if no group is primary
1284     * @throws DBException upon database access error
1285     */

1286    public String JavaDoc getPrimaryGroup() throws DBException {
1287        return getUserInfo().getPrimaryGroup();
1288    }
1289
1290    /**
1291     * utility
1292     *
1293     * @param login the login name
1294     * @param myDBname the DataContext to use.
1295     * @return the integer uid of the given login
1296     * @throws DBException upon databaes access error or if the uid cannot be found.
1297     */

1298    public static int getIdFromLogin(String JavaDoc login, String JavaDoc myDBname) throws DBException {
1299        User user = new User();
1300        user.setDataContext(myDBname);
1301        user.setLoginName(login);
1302        if (!user.find()) {
1303            throw new DBException("cannot find user: " + login);
1304        }
1305
1306        return user.getUid();
1307    }
1308
1309    /**
1310     * Pull up the User object associated with the integer id
1311     *
1312     * @param uid the integer user id
1313     * @param dataContext data context to look in.
1314     * @return a built User object
1315     * @throws DBException if the user is unable to be found.
1316     */

1317    public static User getUserFromId(int uid, String JavaDoc dataContext) throws DBException {
1318        User user = new User();
1319        user.setDataContext(dataContext);
1320        user.setUid(uid);
1321        if (!user.find()) {
1322            throw new DBException("cannot find user: " + uid);
1323        }
1324        return user;
1325    }
1326
1327    /**
1328     * utility
1329     *
1330     * @param uid the uid of the user
1331     * @param dataContext the data context to use
1332     * @return the Login for the given UID
1333     * @throws DBException upon database access error or if the given id cannot be found.
1334     */

1335    public static String JavaDoc getLoginFromId(int uid, String JavaDoc dataContext) throws DBException {
1336        User user = User.getUserFromId(uid, dataContext);
1337        return user.getLoginName();
1338    }
1339
1340
1341    /**
1342     * Given a 'friendly name' get the key value for this object. Example, mappedValue
1343     * = &quot;Admin&quot;, then getKeyValue(&quot;Admin&quot;) will return &quot;3&quot;
1344     *
1345     * @param mappedValue the value to convert to a key field. It will return null
1346     * if the mapped value does not exist.
1347     * @return java.lang.String or null.
1348     */

1349    public String JavaDoc getKeyValue(String JavaDoc mappedValue) {
1350        try {
1351            User u = new User();
1352            u.setDataContext(this.getDataContext());
1353            u.setLoginName(mappedValue);
1354            if (u.find()) {
1355                return u.getUidString();
1356            } else {
1357                return null;
1358            }
1359        } catch (DBException ex) {
1360            log.error("Error getting key value", ex);
1361            return null;
1362        }
1363    }
1364
1365    /**
1366     * Given a key value, return the mapped value. So for example:
1367     * getMappedValue(&quot;3&quot;) will return &quot;Admin&quot;
1368     *
1369     * @param keyValue the key value to map
1370     * @return the mapped value. It will return null if the key does not
1371     * exist
1372     */

1373    public String JavaDoc getMappedValue(String JavaDoc keyValue) {
1374        try {
1375            User u = new User();
1376            u.setDataContext(this.getDataContext());
1377            u.setUid(keyValue);
1378            if (u.find()) {
1379                return u.getLoginName();
1380            } else {
1381                return null;
1382            }
1383        } catch (DBException ex) {
1384            log.error("Error getting key value", ex);
1385            return null;
1386        }
1387
1388    }
1389
1390    /**
1391     * It returns if the field description for the mapped value as specified by the
1392     * key value parameter.
1393     * <p>Total Hack warning: This function assumes you're running a DataObject
1394     * with the login name field called: LoginName
1395     *
1396     * @return String the mapped description
1397     */

1398    public String JavaDoc getMappedDescription() {
1399        try {
1400            return ((DataObject) this.getUserInfo()).getFieldMetaData("LoginName").getDescription();
1401        } catch (DBException ex) {
1402            log.error("Error getting description", ex);
1403            return "Login Name";
1404        } catch (ClassCastException JavaDoc cce) {
1405            return "Login Name";
1406        }
1407    }
1408
1409
1410    /**
1411     * Sets the data context for this particular object implementation.
1412     *
1413     * @param newContext the new Data context.
1414     * @throws IllegalArgumentException if the data context is null.
1415     */

1416    public void setDataContext(String JavaDoc newContext) {
1417        try {
1418            this.setDBName(newContext);
1419        } catch (DBException ex) {
1420            log.error("Error setting data context", ex);
1421            throw new IllegalArgumentException JavaDoc(ex.getMessage());
1422        }
1423    }
1424
1425    /**
1426     * Retrieve the data context for this particular object implementation
1427     *
1428     * @return java.lang.String. Should never be null.
1429     */

1430    public String JavaDoc getDBName() {
1431        return this.getDataContext();
1432    }
1433
1434    /**
1435     * Convenience routine to find current user.
1436     *
1437     * @param request current request
1438     * @return current user
1439     * @throws DBException upon database access error
1440     */

1441    public static User getUser(ControllerRequest request) throws DBException {
1442        return getUserFromId(request.getUid(), request.getDataContext());
1443    }
1444
1445    /**
1446     * determine whether this user is in this group
1447     *
1448     * @param candidategroupname the name to check against.
1449     * @return true if the provided group name is one of the groups that this user is a member of
1450     * @throws DBException upon database access error
1451     */

1452    public boolean isMember(String JavaDoc candidategroupname) throws DBException {
1453        boolean result = false;
1454        List JavaDoc list = getGroupsList();
1455        for (Iterator JavaDoc iterator = list.iterator(); iterator.hasNext();) {
1456            String JavaDoc grpname = (String JavaDoc) iterator.next();
1457            if (grpname.equals(candidategroupname)) {
1458                result = true;
1459                break;
1460            }
1461        }
1462        return result;
1463    }
1464} /* User */
1465
Popular Tags