Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/RuntimeCollective/webapps/bean/UserGroup.java


1   /* $Header: /home/CVS/rjp/src/com/RuntimeCollective/webapps/bean/UserGroup.java,v 1.34 2003/10/13 15:42:43 fabrice Exp $
2    * $Revision: 1.34 $
3    * $Date: 2003/10/13 15:42:43 $
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.BeanComparator;
33  import com.RuntimeCollective.webapps.EntityBeanStore;
34  import com.RuntimeCollective.webapps.RuntimeDataSource;
35  import com.RuntimeCollective.webapps.RuntimeParameters;
36  import com.RuntimeCollective.webapps.SearchResults;
37  import com.RuntimeCollective.webapps.WebappsException;
38  import com.RuntimeCollective.webapps.bean.EntityBean;
39  
40  import java.util.ArrayList;
41  import java.util.List;
42  import java.util.Collection;
43  import java.util.Collections;
44  import java.util.HashSet;
45  import java.util.Iterator;
46  import java.util.Vector;
47  
48  import java.sql.SQLException;
49  
50  /**
51   * A group of users.
52   *
53   * @see com.RuntimeCollective.webapps.form.UserGroupForm
54   *
55   * @version $Id: UserGroup.java,v 1.34 2003/10/13 15:42:43 fabrice Exp $
56   */
57  public class UserGroup implements EntityBean, Collection {
58  
59  
60      /** 
61       * The name of a table (in the default database) that indexes this bean type. 
62       * This table must have a PK column called "id" and a row for each of the beans of this type. 
63       */
64      public static final String DATABASE_TABLE = "user_group";
65  
66      /** The table that maps users to groups. */
67      public static final String MEMBERSHIP_TABLE = "user_group_map";
68  
69      private static final String SELECT_ID = "select id from ";
70      private static final String DELETE_FROM = "delete from ";
71      private static final String SELECT_DATA = "select t.name, t.type_id from "; 
72      private static final String WHERE_ID = " where id = ";
73      private static final String WHERE_T_ID = " t where t.id = ";
74      private static final String INSERT_INTO = "insert into ";
75      private static final String DATA_VALUES = " (group_id,user_id) values (";
76      private static final String WHERE_GROUP_ID = " where group_id = ";
77      private static final String AND_USER_ID = " and user_id = ";
78      private static final String SELECT_USER_ID = "select user_id from ";
79      private static final String SELECT_ID_NAME = "select id, name from ";
80      private static final String FIRST_NAME = "firstName";
81      private static final String NAME = "name";
82      private static final String TYPE_ID = "type_id";
83      private static final String WHERE_TYPE_ID = " where type_id = ";
84      private static final String WHERE_NAME = " where name = '";
85  
86      private static final String AND = " and ";
87      private static final String LAST_USED = " - last_used_date < 60 * ";
88      private static final String SPACE = " ";
89      private static final String SPACE_OPEN = " (";
90      private static final String CLOSE = ")";
91      private static final String ESC = "'";
92      private static final String COMMA = ",";
93      private static final String END_PAR = ")";
94  
95  
96      // == Instance variables ===================================================
97  
98      /** Unique identifier */
99      private int iId;
100 
101     /** The name of this user group. */
102     private String iName = "";
103 
104     /** The type of this user group. */
105     private int iTypeId = EntityBean.NULL_ID;
106 
107     /** A list of Users to add to this UserGroup, when next saved. */
108     private List addBuffer;
109  
110     /** A list of Users to remove from this UserGroup, when next saved. */
111     private List removeBuffer;
112  
113 
114 
115     // == Constructors ===================================================
116 
117 
118     /** Default constructor generates a new blank bean with a new unique ID.
119     */
120     public UserGroup() {
121         try {
122             setId( RuntimeDataSource.nextId() );
123             addBuffer = Collections.synchronizedList(new ArrayList());
124             removeBuffer = Collections.synchronizedList(new ArrayList());
125             if (!RuntimeParameters.isClustered()) {
126                 cachedUserIds = Collections.synchronizedList(new ArrayList());
127             }
128         } catch( Exception e ) {
129             RuntimeParameters.logError( this, "Problem getting new id", e );
130             throw new WebappsException( "Problem getting new id "+e );
131         }
132     }
133 
134 
135     /** Generate a bean from the database for the given primary key.
136     * @param id The primary key of the bean to find.
137     */
138     public UserGroup( int id ) {
139         
140         EntityBeanStore store = RuntimeParameters.getStore();
141   
142         try {
143 
144             // Construct the group
145             Object[] results = RuntimeDataSource.queryRow(SELECT_DATA+DATABASE_TABLE+WHERE_T_ID+id );
146              if (results.length == 2) {
147                 setId( id );
148                 if (results[0] != null) {
149                     setName( results[0].toString() );
150                 }
151                 if ( results[1]!=null ) {
152                     setType( (UserGroupType) store.get(UserGroupType.class.getName(), Integer.parseInt( results[1].toString() ) ) );
153                 }
154             } else {
155                 RuntimeParameters.logError( this, "no user group found for id = "+id );
156                 throw new WebappsException( "no user group found for id = "+id );
157             }
158             
159             // Make the add/remove buffers
160             addBuffer = Collections.synchronizedList(new ArrayList());
161             removeBuffer = Collections.synchronizedList(new ArrayList());
162             
163             // Populate the cache of user ids
164             if (!RuntimeParameters.isClustered()) {
165                 int[] ids = RuntimeDataSource.queryInts((new StringBuffer(60)).append(SELECT_USER_ID).append(MEMBERSHIP_TABLE).append(WHERE_GROUP_ID).append(getId()).toString());            
166                 cachedUserIds = Collections.synchronizedList(new ArrayList(ids.length+10));
167                 for (int i=0; i<ids.length; i++) {
168                     cachedUserIds.add(new Integer(ids[i]));
169                 }
170             }
171             
172         } catch ( Exception e ) {
173             e.printStackTrace();
174             RuntimeParameters.logError( this, "problem getting user group with id = "+id, e );
175             throw new WebappsException( e );
176         }        
177     }
178 
179 
180 
181     // == Bean property methods ===================================================
182 
183     /** Get unique identifier */
184     public int getId() { return iId; }
185 
186 
187     /** Set unique identifier */
188     public void setId(int id) { iId = id; }
189 
190 
191     /** Get the name of this user group. */
192     public String getName() { return iName; }
193 
194 
195     /** Set the name of this user group. */
196     public void setName(String name) { iName = name; }
197 
198 
199     /** Get the type of this user group. (optional) */
200     public UserGroupType getType() { 
201   if (iTypeId == EntityBean.NULL_ID) {
202       return null;
203   } else {
204       return (UserGroupType) RuntimeParameters.getStore().get(UserGroupType.class.getName(), iTypeId);
205   }
206     }
207 
208 
209     /** Set the type of this user group. (optional) */
210     public void setType(UserGroupType type) {
211   if (type == null) {
212       iTypeId = EntityBean.NULL_ID;
213   } else {
214       iTypeId = type.getId(); 
215   }
216     }
217 
218 
219     /** Returns an iterator over the users in this group. */
220     public Iterator getUsers() {
221   return iterator();
222     }
223 
224     /** Get the users as an alphabetically-ordered list of users. */
225     public List getUsersSortedList() {
226   // sort the UserGroup (a collection) by cloning it into a List
227   List sortedUserGroup = Collections.synchronizedList(new ArrayList());
228   synchronized(sortedUserGroup) {
229       Iterator it = iterator();
230       while (it.hasNext())
231     sortedUserGroup.add(it.next());
232   }
233   Collections.sort(sortedUserGroup, new BeanComparator(FIRST_NAME, true, true));
234   return sortedUserGroup;
235     }
236 
237 
238     // == Entity Bean methods ===========================================
239 
240     /** A cache of the user ids saved to the db. */
241     protected List cachedUserIds;
242 
243     /** Save this bean to the database. */
244     public void save() {
245   try {
246 
247         // clear the cache for this group, if not clustered
248         if (!RuntimeParameters.isClustered()) {
249             RuntimeParameters.getUserGroups().clearFromGroupNameCache(getId());
250         }
251 
252       // Save basic group details
253       RuntimeDataSource.save( getId(), DATABASE_TABLE,
254             new String[] { NAME, TYPE_ID },
255             new Object[] { getName(), getType() }
256             );
257 
258       Vector sqls = new Vector();
259         
260       // Add all users to be added, then wipe the buffer (and update the cache)
261       synchronized(addBuffer) {
262             Iterator i = addBuffer.iterator();
263             User user;
264             while (i.hasNext()) {
265                 user = userFromId(i.next());
266                 sqls.add(INSERT_INTO+MEMBERSHIP_TABLE+DATA_VALUES+getId()+COMMA+user.getId()+END_PAR);
267                 if (!RuntimeParameters.isClustered()) {
268                     cachedUserIds.add(new Integer(user.getId()));
269                 }
270             }
271             addBuffer.clear();
272       }
273 
274       // Remove all users to be removed, then wipe the buffer (and update the cache)
275       synchronized(removeBuffer) {
276             Iterator i = removeBuffer.iterator();
277             User user;
278             while (i.hasNext()) {
279                 user = userFromId(i.next());
280                 sqls.add(DELETE_FROM+MEMBERSHIP_TABLE+WHERE_GROUP_ID+getId()+AND_USER_ID+user.getId() );
281                 if (!RuntimeParameters.isClustered()) {
282                     cachedUserIds.remove(new Integer(user.getId()));
283                 }
284             }
285             removeBuffer.clear();
286       }
287     
288       RuntimeDataSource.update( sqls );
289 
290   } catch (Exception e) {
291       RuntimeParameters.logError( this, "problem saving user group id="+getId(), e );
292       throw new WebappsException( "problem saving user group id="+getId() );
293   }
294     }
295 
296 
297     /** Delete this bean from the database. */
298     public void delete() {
299   try {
300       
301         // clear the cache for this group, if not clustered
302         if (!RuntimeParameters.isClustered()) {
303             RuntimeParameters.getUserGroups().clearFromGroupNameCache(getId());
304         }
305 
306       // Delete all users and group details
307       // NB the delete cascade trigger should handle this; but can't hurt to do it seperately
308       RuntimeDataSource.update( new String[] {
309             DELETE_FROM+MEMBERSHIP_TABLE+WHERE_GROUP_ID+getId(),
310             DELETE_FROM+DATABASE_TABLE+WHERE_ID+getId() } );
311       
312   } catch (Exception e) {
313       RuntimeParameters.logError( this, "problem deleting user group id="+getId(), e );
314       throw new WebappsException( "problem deleting user group id="+getId() );
315   }
316     }
317 
318 
319     // == Collection methods =============================================
320  
321 
322     /** Add a user to this group. 
323      * <p>(The user will not actually be added until the UserGroup is saved.)
324      * @exception WebappsException thrown if o is not a user.
325      */
326     public boolean add(Object o) {
327   try {
328       Integer userId = idFromUser(o);
329 
330       // Remove from the "remove" buffer, if present
331       boolean removeChanged = removeBuffer.remove( userId );
332 
333       // Add to the "add" buffer
334       boolean addChanged = !addBuffer.add( userId );
335 
336       // Have we changed the add/remove buffers?
337       boolean changed = addChanged || removeChanged;
338       
339       // if we weren't adding/removing this user already,
340       // check the existing user group to see if this
341       // action will change it
342       if (addChanged && !removeChanged) {
343     changed = !contains(o);
344       }
345 
346       return changed;
347 
348   } catch (ClassCastException e) {
349       RuntimeParameters.logError( this, "Trying to add non user object "+o+" to UserGroup", e );
350       throw new WebappsException( e );
351   }
352     }
353 
354 
355     /** Add a collection of users to this group.
356      * @exception WebappsException thrown if c contains an object that is not a user.
357      */
358     public boolean addAll(Collection c) {
359 
360   Iterator it = c.iterator();
361   Object o;
362 
363   boolean modified = false;
364 
365   // check types of objects being added 
366   while ( it.hasNext() ) {
367       o = it.next();
368       try {
369     modified = modified || add( o );
370       } catch (ClassCastException e) {
371     RuntimeParameters.logError( this, "Trying to add non user object "+o+" to UserGroup" );
372     throw new WebappsException( "Trying to add non user object "+o+" to UserGroup" );
373       } 
374   }
375 
376   return modified;
377     }
378 
379 
380     /** Remove all users from this group. */
381     public void clear() {
382         // removeAll(getAllUsers());
383         
384         // FR: this shoud be much quicker, and doesn't load the users
385       addBuffer.clear();
386         if (!RuntimeParameters.isClustered()) {
387             cachedUserIds.clear();
388         }
389       removeBuffer.addAll(getAllUserIds());
390     }
391 
392 
393     /** Returns true if the specified user is in this group 
394      */
395     public boolean contains(Object o) {
396         // return getAllUsers().contains(o);
397 
398         // FR: this doesn't load the users
399         if (o == null) {
400             return false;
401         }
402         return getAllUserIds().contains(new Integer(((User) o).getId()));
403     }
404 
405 
406     /** Returns true if this group contains a collection of users. */
407     public boolean containsAll(Collection c) {
408         // return getAllUsers().containsAll( c );
409 
410         // FR: bit more complicated, but doesn't load the users
411         if (c == null) {
412             return true;
413         }
414         List ids = new ArrayList(c.size());
415         for (Iterator it = c.iterator(); it.hasNext(); ) {
416             ids.add(new Integer(((User) it.next()).getId()));
417         }
418         return getAllUserIds().containsAll(ids);
419     }
420 
421 
422     /** Compares the specified object with this group for equality. */
423     /*
424     public boolean equals(Object o) {
425   return iUsers.equals( idFromUser(o) );
426     }
427     */
428 
429     /** Returns the hash code value for this group. */
430     public int hashCode() {
431   return getAllUsers().hashCode();
432     }
433 
434 
435     /** Returns true if this group contains no users. */
436     public boolean isEmpty() {
437         // return getAllUsers().isEmpty();
438 
439         // FR: this doesn't load the users
440         return getAllUserIds().isEmpty();
441     }
442 
443 
444     /** Returns an iterator over the users in this group. */
445     public Iterator iterator() {
446         return getAllUsers().iterator();
447     }
448 
449 
450     /** Removes a single instance of the specified user from this group, if it is present. */
451     public boolean remove(Object o) {
452   try {
453       Integer userId = idFromUser(o);
454 
455       // Remove from the "add" buffer, if present
456       boolean addChanged = addBuffer.remove( userId );
457 
458       // Add to the "remove" buffer
459       boolean removeChanged = !removeBuffer.add( userId );
460 
461       // Have we changed the add/remove buffers?
462       boolean changed = removeChanged || addChanged;
463       
464       // if we weren't adding/removing this user already,
465       // check the existing user group to see if this
466       // action will change it
467       if (removeChanged && !addChanged) {
468             changed = contains(o);
469       }
470 
471       return changed;
472 
473   } catch (ClassCastException e) {
474       RuntimeParameters.logError( this, "Trying to remove non user object "+o+" to UserGroup", e );
475       throw new WebappsException( e );
476   }
477     }
478 
479 
480     /** Removes all this group's users that are also contained in the specified collection. */  
481     public boolean removeAll(Collection c) {
482         Iterator it = c.iterator();
483         Object o;
484 
485         boolean modified = false;
486 
487         // check types of objects being added 
488         while ( it.hasNext() ) {
489             o = it.next();
490             try {
491                 modified = modified || remove( o );
492             } catch (ClassCastException e) {
493                 RuntimeParameters.logError( this, "Trying to remove non user object "+o+" from UserGroup" );
494                 throw new WebappsException( "Trying to remove non user object "+o+" from UserGroup" );
495             } 
496         }
497         
498         return modified;
499     }
500 
501 
502     /** Retains only the users in this group that are contained in the specified collection. */
503     public boolean retainAll(Collection c) {
504         boolean modified = false;
505         Iterator i = iterator();
506         Object o;
507         
508         while (i.hasNext()) {
509             o = i.next();
510             if (!c.contains(o)) {
511                 modified = modified || remove( o );
512             }
513         }
514         
515         return modified;
516     }
517 
518 
519     /** Returns the number of users in this group. */
520     public int size() {
521         // return getAllUsers().size();
522 
523         // FR: this doesn't load the users
524         return getAllUserIds().size();
525     }
526 
527 
528     /** Returns an array of Users in this group
529      * @return an array of Users
530      */
531     public Object[] toArray() {
532   return getAllUsers().toArray( new User[] {} );
533     }
534 
535 
536     /** Returns an array of Users in this group, using the specified array, if possible.
537      * 
538      * @param a the array into which the elements of the list are to
539      *    be stored, if it is big enough; otherwise, a new array of the
540      *     same runtime type is allocated for this purpose.
541      * @return an array containing the elements of the list.
542      */
543     public Object[] toArray( Object[] a ) {
544   return getAllUsers().toArray(a);
545     }
546 
547 
548 
549 
550     // == Private methods ==================================================
551 
552     /**
553      * Get all users in this usergroup, by getting
554      * the list of ids and loading all the users from the EBS.
555      */
556     private Collection getAllUsers() {
557         return usersFromIds(getAllUserIds());
558     }
559 
560 
561     /**
562      * Get the ids of all users in this usergroup.
563      * If clustered, this queries the the database every time.
564      * Otherwise we use the cache.
565      * It takes into account users in the add/remove buffers
566      * that have not been saved yet.
567      */
568     private Collection getAllUserIds() {
569         try {
570             ArrayList iUsers = null;
571 
572             if (RuntimeParameters.isClustered()) {
573                 // clustered - don't use the cache
574 
575                 // Get all the user ids in this group
576                 int[] ids = RuntimeDataSource.queryInts((new StringBuffer(60)).append(SELECT_USER_ID).append(MEMBERSHIP_TABLE).append(WHERE_GROUP_ID).append(getId()).toString());            
577                 iUsers = new ArrayList(ids.length+10);
578                 for (int i=0; i<ids.length; i++) {
579                     iUsers.add(new Integer(ids[i]));
580                 }
581 
582             } else {
583                 iUsers = new ArrayList(cachedUserIds.size()+10);
584                 iUsers.addAll(cachedUserIds);
585             }
586 
587             // add those in the "add" buffer
588             synchronized(addBuffer) {
589                 Iterator i = addBuffer.iterator();
590                 while (i.hasNext()) {
591                     iUsers.add(i.next());
592                 }
593             }
594             
595             // remove those in the "remove" buffer
596             // (a User should not be in both buffers)
597             synchronized(removeBuffer) {
598                 Iterator i = removeBuffer.iterator();
599                 while (i.hasNext()) {
600                     iUsers.remove(i.next());
601                 }
602             }
603             
604             return iUsers;
605             
606         } catch (Exception e) {
607             RuntimeParameters.logError(this, "UserGroup: Problem fetching user ids from db: ", e);
608             throw new WebappsException("UserGroup: Problem fetching user ids from db: "+e);
609         }
610     }
611 
612 
613     // == Static methods ==================================================
614     // NOTE: all these methods have been deprecated, and moved to webapps.UserGroups
615 
616     /** Get a list of all the user groups. 
617      * @deprecated Instead, use <code>RuntimeParameters.getUserGroups().getAllGroups()</code>
618      * @see com.RuntimeCollective.webapps.UserGroups#getAllGroups()
619      */
620     public static SearchResults getAllGroups() {
621   // NB we return a SearchResults with a description of each group, rather than an iterator of them, so that we avoid instantiating all groups (and potentially all users) wherever possible. 
622   try {
623       return RuntimeDataSource.search(SELECT_ID_NAME+DATABASE_TABLE );
624   } catch (Exception e) {
625       RuntimeParameters.logError(UserGroup.class.getName(), "Problem finding groups", e);
626       throw new WebappsException(e);
627   }
628     }
629 
630 
631     /** Get a list of all the user groups of the given type. 
632      * @deprecated Instead, use <code>RuntimeParameters.getUserGroups().getAllGroups(UserGroupType type)</code>
633      * @see com.RuntimeCollective.webapps.UserGroups#getAllGroups(com.RuntimeCollective.webapps.bean.UserGroupType)
634      */
635     public static SearchResults getAllGroups( UserGroupType type ) {
636   // NB we return a SearchResults with a description of each group, rather than an iterator of them, so that we avoid instantiating all groups (and potentially all users) wherever possible. 
637   try {
638       return RuntimeDataSource.search(SELECT_ID_NAME+DATABASE_TABLE+WHERE_TYPE_ID+type.getId() );
639   } catch (Exception e) {
640       RuntimeParameters.logError(UserGroup.class.getName(), "Problem finding groups", e );
641       throw new WebappsException(e);
642   }
643     }
644 
645 
646     /** Get a user group for the given name.
647      * @deprecated Instead, use <code>RuntimeParameters.getUserGroups().getForName(String name)</code>
648      * @see com.RuntimeCollective.webapps.UserGroups#getForName(java.lang.String)
649      * @return The user group with the given name, or null if none exists
650      */
651     public static UserGroup getForName( String name ) {
652   try {
653       int[] id = RuntimeDataSource.queryInts(SELECT_ID+DATABASE_TABLE+WHERE_NAME+RuntimeDataSource.escape(name)+ESC);
654       if ( id.length==0 ) return null;
655       else return (UserGroup) RuntimeParameters.getStore().get(UserGroup.class.getName(), id[0] );
656   } catch (SQLException e) {
657       RuntimeParameters.logError(UserGroup.class.getName(), "Problem finding groups for name="+name, e );
658       throw new WebappsException(e);
659   }
660     }
661 
662     /**
663      * Returns the ID of a User object, if indeed this object is a User
664      * @exception ClassCastException if <code>o</code> is not a User
665      */
666     protected Integer idFromUser(Object o) throws ClassCastException {
667   return new Integer( ((User) o).getId());
668     }
669 
670     /**
671      * Returns a User from an Integer object , if indeed this object is an Integer
672      * @exception ClassCastException if <code>o</code> is not a Integer
673      */
674     protected User userFromId(Object o) throws ClassCastException {
675   return (User)RuntimeParameters.getStore().get(User.class.getName(), ((Integer)o).intValue());
676     }
677 
678     /**
679      * Takes a Collection of Users, and returns
680      * a Collection of their ids, as Integers.
681      */
682     protected Collection idsFromUsers(Collection c) {
683   ArrayList a = new ArrayList();
684   Iterator it = c.iterator();
685   while (it.hasNext()) {
686       a.add( idFromUser(it.next()) );
687   }
688   return a;
689     }
690 
691     /**
692      * Takes a Collection of Integer ids, and returns
693      * a Collection of the corresponding Users.
694      */
695     protected Collection usersFromIds(Collection c) {
696         ArrayList a = new ArrayList();
697         Iterator it = c.iterator();
698         while (it.hasNext()) {
699             int i = ((Integer) it.next()).intValue();
700             a.add(RuntimeParameters.getStore().get(User.class.getName(), i));
701         }
702         return a;
703     }
704 } 
705 
706