Source code: com/RuntimeCollective/webapps/bean/SimpleUser.java
1 /* $Header: /home/CVS/rjp/src/com/RuntimeCollective/webapps/bean/SimpleUser.java,v 1.32 2003/09/30 15:13:10 joe Exp $
2 * $Revision: 1.32 $
3 * $Date: 2003/09/30 15:13:10 $
4 *
5 * ====================================================================
6 *
7 * Josephine : http://www.runtime-collective.com/josephine/index.html
8 *
9 * Copyright (C) 2003 Runtime Collective
10 *
11 * This product includes software developed by the
12 * Apache Software Foundation (http://www.apache.org/).
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 */
29
30 package com.RuntimeCollective.webapps.bean;
31
32 import com.RuntimeCollective.webapps.RuntimeDataSource;
33 import com.RuntimeCollective.webapps.EntityBeanStore;
34 import com.RuntimeCollective.webapps.RuntimeParameters;
35 import com.RuntimeCollective.webapps.bean.User;
36 import com.RuntimeCollective.webapps.SearchResults;
37 import com.RuntimeCollective.webapps.form.SearchUserForm;
38 import com.RuntimeCollective.webapps.DateUtils;
39
40 import java.sql.SQLException;
41 import java.io.IOException;
42 import java.util.Vector;
43 import java.util.Date;
44 import java.util.Hashtable;
45 import java.math.BigDecimal;
46
47
48 /**
49 * Simple implementation of the User interface representing
50 * a user that has an address.
51 *
52 * @version $Id: SimpleUser.java,v 1.32 2003/09/30 15:13:10 joe Exp $
53 */
54 public class SimpleUser implements User {
55
56 /** name of interface used to identify this bean */
57 public static final String INTERFACE_BEAN = "com.RuntimeCollective.webapps.bean.User";
58
59 /** The name of the database table for this bean type. */
60 public static final String DATABASE_TABLE = "rs_user";
61
62 private static final String SELECT_DATE = "SELECT id,email,password,first,surname,create_date,address_id FROM rs_user WHERE id=";
63 private static final String ARCHIVE_DATE_NULL = " AND archive_date is NULL";
64 private static final String SELECT_ROLES = "SELECT role FROM rs_user_role WHERE rs_user=";
65 private static final String EMAIL = "email";
66 private static final String PASSWORD = "password";
67 private static final String FIRST = "first";
68 private static final String SURNAME = "surname";
69 private static final String ADDRESS_ID = "address_id";
70 private static final String CREATE_DATE = "create_date";
71 private static final String DELETE_ROLES = "DELETE FROM rs_user_role WHERE rs_user=";
72 private static final String INSERT_ROLE = "INSERT INTO rs_user_role(rs_user,role) VALUES (";
73 private static final String COMMA = ",";
74 private static final String END_PAR = ")";
75 private static final String UPDATE = "update ";
76 private static final String SET_ARCHIVE_DATE = " set archive_date=";
77 private static final String SET_ARCHIVE_DATE_NULL = " SET archive_date=NULL WHERE id=";
78 private static final String WHERE_ID = " WHERE id=";
79 private static final String DELETE_WHERE = "delete from rs_user where id=";
80 private static final String SELECT_ID_WHERE_EMAIL = "SELECT id FROM rs_user WHERE lower(email)='";
81
82 // sql fragments used in search
83
84 private static final String RESULTS = " u.id, u.first||' '||u.surname||' ('||u.email||')'";
85 private static final String USER_TABLE = " rs_user u";
86 private static final String ROLE_TABLE = ", rs_user_role r";
87 private static final String ADDRESS_TABLE = ", common_address a";
88 private static final String ROLE_JOIN = " r.rs_user=u.id AND ";
89 private static final String ADDRESS_JOIN = " a.id=u.address_id AND ";
90 private static final String NOT_ARCHIVED_CONDITION = " u.archive_date IS NULL AND ";
91 private static final String FIRST_LIKE = "LOWER(u.first) LIKE '";
92 private static final String SURNAME_LIKE = "LOWER(u.surname) LIKE '";
93 private static final String CITY_LIKE = "LOWER(a.city)='";
94 private static final String COUNTRY_LIKE = "LOWER(a.country)='";
95 private static final String NATIONALITY_LIKE = "LOWER(a.nationality)='";
96 private static final String EMAIL_LIKE = "LOWER(u.email) LIKE '";
97 private static final String POSTCODE_LIKE = "LOWER(a.postcode) LIKE '";
98 private static final String SELECT = "SELECT ";
99 private static final String FROM = " FROM ";
100 private static final String WHERE = " WHERE ";
101 private static final String ORDER_BY = " ORDER BY LOWER(u.first),LOWER(u.surname)";
102 private static final String LIKE_AND = "%' AND ";
103 private static final String AND = "' AND ";
104 private static final String NOTHING = "";
105 private static final String ESC = "'";
106
107
108 // == Constructor =================================================
109
110 /** Construct a new blank user, giving it a new unique ID.
111 * This will also create a new Address object for this user.
112 */
113 public SimpleUser() throws SQLException {
114 this.id = RuntimeDataSource.nextId();
115 // Set creation date to now
116 setCreateDate( new Date() );
117 // Set address to a new address
118 setAddress((Address) RuntimeParameters.getStore().create(Address.class.getName()));
119 }
120
121 /** Get a current user from the RuntimeDataSource, given an id.
122 * @param id ID of user.
123 * @exception SQLException is thrown if no such user exists.
124 */
125 public SimpleUser(int id) throws SQLException {
126 Object[] result = RuntimeDataSource.queryRow(SELECT_DATE+id+ARCHIVE_DATE_NULL);
127 if ( result != null ) {
128
129 // Get the basic user details
130 setId( Integer.parseInt( result[0].toString() ) );
131 setEmail( (String) result[1] );
132 setPassword( (String) result[2] );
133 setFirstName( (String) result[3] );
134 setLastName( (String) result[4] );
135 if (result[5] != null)
136 setCreateDate(RuntimeDataSource.toDate(result[5].toString()));
137 else
138 setCreateDate(null);
139 if (result[6] != null)
140 setAddress( (Address) RuntimeParameters.getStore().get(Address.class.getName(), Integer.parseInt( result[6].toString() ) ) );
141
142 // Get the user roles.
143 int[] roles = RuntimeDataSource.queryInts(SELECT_ROLES+id );
144 setRoles( roles );
145 }
146 }
147
148
149 /** Save this user to the RuntimeDataSource.
150 */
151 public void save() throws SQLException {
152
153 // Save address
154 if ( address!=null ) RuntimeParameters.getStore().save( address );
155
156 // Add new user
157 RuntimeDataSource.save( id, DATABASE_TABLE,
158 new String[] { EMAIL, PASSWORD, FIRST, SURNAME, ADDRESS_ID, CREATE_DATE },
159 new Object[] { email, password, firstName, lastName, address, (Date) createDate } );
160
161 // Save user roles
162 Vector sql = new Vector();
163 sql.add(DELETE_ROLES+id);
164 for (int i=0; i<roles.length; i++) {
165 sql.add(INSERT_ROLE+id+COMMA+roles[i]+END_PAR);
166 }
167 RuntimeDataSource.update( sql );
168
169 }
170
171 /** Archive this bean.
172 * @exception SQLException if unable to connect to the database.
173 */
174 public void archive() throws SQLException {
175 RuntimeDataSource.update(UPDATE+DATABASE_TABLE+SET_ARCHIVE_DATE+RuntimeDataSource.toSqlString(DateUtils.getCurrentDate())+WHERE_ID+id);
176 }
177
178 /** Unarchive this bean.
179 * @exception SQLException if unable to connect to the database.
180 */
181 public void unArchive() throws SQLException {
182 RuntimeDataSource.update(UPDATE+DATABASE_TABLE+SET_ARCHIVE_DATE_NULL+id);
183 }
184
185 /** Delete this bean from the database.
186 * @exception SQLException if unable to connect to the database.
187 */
188 public void delete() throws SQLException {
189 RuntimeDataSource.update(DELETE_WHERE+id);
190 if ( address!=null ) RuntimeParameters.getStore().delete( address );
191 }
192
193 // == Properties ===================================================
194
195 /** ID */
196 protected int id;
197 /** Get the user's ID. */
198 public int getId() { return (this.id); }
199 /** Set the user's ID. */
200 public void setId(int id) { this.id = id; }
201
202 /** Email address -- used as a unique identifier when logging in. */
203 protected String email = null;
204 /** Get the user's email address -- used as a unique identifier when logging in. */
205 public String getEmail() { return (this.email); }
206 /** Set the user's email address -- used as a unique identifier when logging in. */
207 public void setEmail(String email) { this.email = email; }
208
209 /** Password. */
210 protected String password = null;
211 /** Get the user's password. */
212 public String getPassword() { return (this.password); }
213 /** Set the user's password. */
214 public void setPassword(String password) { this.password = password; }
215
216 /** The date that the user was registered onto the system. */
217 protected Date createDate = null;
218 /** Set the date that the user was registered onto the system. */
219 public void setCreateDate(Date createDate) { this.createDate = createDate; }
220 /** Get the date that the user was registered onto the system. */
221 public Date getCreateDate() { return this.createDate; }
222
223 /* The array of roles the user has been assigned. */
224 protected int[] roles = new int[] {};
225 /* Get the array of roles held by this user.
226 * <p> <i>Roles are intended to be very simple identifiers for users. If you require more complex ways of grouping users, then try using UserGroups. </i>
227 */
228 public int[] getRoles() { return this.roles; }
229 /* Set the array of roles.
230 * <p> <i>Roles are intended to be very simple identifiers for users. If you require more complex ways of grouping users, then try using UserGroups. </i>
231 */
232 public void setRoles(int[] roles) { this.roles = roles; }
233
234 /* Check whether the user has the role.
235 * <p> <i>Roles are intended to be very simple identifiers for users. If you require more complex ways of grouping users, then try using UserGroups. </i>
236 *
237 * @return true if the user has the role. false otherwise. */
238 public boolean hasRole(int role) {
239 for (int i=0; i<getRoles().length; i++) {
240 if (this.roles[i]==role) return true;
241 }
242 return false;
243 }
244
245 /** First name */
246 protected String firstName = "";
247 /** Get first name */
248 public String getFirstName() { return this.firstName; }
249 /** Set first name */
250 public void setFirstName(String firstName) { this.firstName = firstName; }
251
252 /** Last name */
253 protected String lastName = "";
254 /** Get last name */
255 public String getLastName() { return this.lastName; }
256 /** Set last name */
257 public void setLastName(String lastName) { this.lastName = lastName; }
258
259 /** The address object of this user. */
260 protected Address address = null;
261 /** Get the address object of this user. */
262 public Address getAddress() { return this.address; }
263 /** Set the address object of this user. */
264 public void setAddress(Address address) { this.address = address; }
265
266
267 // == Other methods ====================================================
268
269 /** Search for current users that match the parameters on the UserSearchForm.
270 * The search form must be validated before this method is called.
271 * @param form A UserSearchForm containing the criteria to search on.
272 * @return A <code>SearchResults</code> of users that match ALL the criteria on the form, or <code>null</code> if none were found. Each result is in the form [id, "firstname surname (email@address)"]
273 */
274 public static SearchResults searchUsers(SearchUserForm form) throws SQLException {
275
276 String stringPrefix = "%";
277 if (form.getStartsOnly())
278 stringPrefix = "";
279
280 // The tables we select from depends on whether we are selecting by role and or address.
281 StringBuffer tables = new StringBuffer(100);
282 StringBuffer conditions = new StringBuffer(100);
283 tables.append( USER_TABLE );
284 conditions.append( NOT_ARCHIVED_CONDITION );
285 if ( form.getRole()>-1 ) {
286 tables.append( ROLE_TABLE );
287 conditions.append( ROLE_JOIN );
288 }
289 if ( form.getCity().length()>0 || !form.getCountry().equals("") || !form.getNationality().equals("") || form.getPostcode().length()>0 ) {
290 tables.append( ADDRESS_TABLE );
291 conditions.append( ADDRESS_JOIN );
292 }
293
294 // Match search parameters
295
296 if ( form.getFirstName().length()>0 )
297 conditions.append(FIRST_LIKE).append(stringPrefix).append( RuntimeDataSource.escape( form.getFirstName().toLowerCase() ) ).append( LIKE_AND);
298
299 if ( form.getLastName().length()>0 )
300 conditions.append(SURNAME_LIKE).append(stringPrefix).append( RuntimeDataSource.escape( form.getLastName().toLowerCase() ) ).append( LIKE_AND);
301
302 if ( form.getCity().length()>0 )
303 conditions.append(CITY_LIKE).append( RuntimeDataSource.escape( form.getCity().toLowerCase() ) ).append( AND);
304
305 if ( !form.getCountry().equals(NOTHING) )
306 conditions.append(COUNTRY_LIKE).append( RuntimeDataSource.escape( form.getCountry().toLowerCase() ) ).append( AND);
307
308 if ( !form.getNationality().equals(NOTHING) )
309 conditions.append(NATIONALITY_LIKE).append( RuntimeDataSource.escape( form.getNationality().toLowerCase() ) ).append( AND);
310
311 if ( form.getEmail().length()>0 )
312 conditions.append(EMAIL_LIKE).append(stringPrefix).append( RuntimeDataSource.escape( form.getEmail().toLowerCase() ) ).append( LIKE_AND);
313
314 if ( form.getPostcode().length()>0 )
315 conditions.append(POSTCODE_LIKE).append(stringPrefix).append( RuntimeDataSource.escape( form.getPostcode().toLowerCase() ) ).append( LIKE_AND);
316
317 // Strip the trailing " AND "
318 int lastChar = conditions.length();
319 conditions.delete(lastChar - 4, lastChar);
320
321 StringBuffer sql = new StringBuffer(200);
322
323 sql.append(SELECT)
324 .append(RESULTS).append(FROM)
325 .append(tables.toString())
326 .append(WHERE)
327 .append(conditions.toString())
328 .append(ORDER_BY);
329
330 return RuntimeDataSource.search( sql.toString() );
331 }
332
333
334 /* Assign a user a role.*/
335 public void addRole(int role) throws SQLException {
336 if (!hasRole(role)) {
337 // Copy the old roles onto a new array
338 int[] newRoles = new int[ getRoles().length+1 ];
339 int i;
340 for (i=0; i<getRoles().length; i++ ) newRoles[i] = roles[i];
341 // And add the new role
342 newRoles[i] = role;
343 setRoles( newRoles );
344 }
345 }
346
347 /* Remove role from a user. */
348 public void removeRole(int role) throws SQLException {
349 if (hasRole(role)) {
350 // Copy the old roles onto a new array
351 int[] newRoles = new int[ getRoles().length-1 ];
352 int j=0;
353 for (int i=0; i<getRoles().length; i++ ) if ( roles[i]!=role ) newRoles[j++] = roles[i];
354 setRoles( newRoles );
355 }
356 }
357
358
359 /** Get the id of a user from the RuntimeDataSource, given an email address.
360 * @param current Whether to find just current (ie non-archived) users.
361 * @param email Email address of user.
362 * @return The id of a user registered for that email address, or -1 if no user exists.
363 */
364 public static int findByEmail( String email, boolean current ) throws SQLException {
365 email = email.toLowerCase();
366 int[] results = RuntimeDataSource.queryInts(SELECT_ID_WHERE_EMAIL + RuntimeDataSource.escape(email) + ESC + (current ? ARCHIVE_DATE_NULL : NOTHING) );
367 if ( results.length>0 ) return results[0];
368 else return -1;
369 }
370
371 /** Get the name (<i>first surname</i>) of a user for a particular id.
372 */
373 public static String getName( int id ) throws SQLException {
374 return getProperty(id, "first ||' '|| surname");
375 }
376
377 /** Get a named property of a user for a particular id.
378 */
379 public static String getProperty( int id , String propertyName ) throws SQLException {
380 return (RuntimeDataSource.
381 queryRow("SELECT " + propertyName + " from rs_user WHERE id="+id)[0]).toString();
382 }
383
384
385 // == Attributes ==================================================
386
387 /** The attributes of this user. */
388 public Hashtable attributes = new Hashtable();
389
390 /** Get the value of an attribute.
391 * <br>
392 * These attributes are *not* saved.
393 * <br>
394 * Null is returned if the attribute for this name has not been. Note that these attributes held on here should be relevant to all users of the system, such as bookmarks or webfolders. If there is an attribute that is specific to a particular type of user, or actor, then it should be held on the relevant Actor object.
395 */
396 public Object getAttribute( String name ) {
397 return attributes.get( name );
398 }
399
400 /** Set the value of an attribute.
401 * <br>
402 * These attributes are *not* saved.
403 * <br>
404 * Note that these attributes held on here should be relevant to all users of the system, such as bookmarks or webfolders. If there is an attribute that is specific to a particular type of user, or actor, then it should be held on the relevant Actor object.
405 */
406 public void setAttribute( String name, Object value ) {
407 attributes.put( name, value );
408 }
409
410 public String toString() {
411 return new String("[FirstName: " + getFirstName() + "][LastName: " + getLastName() + "]");
412 }
413 }