KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > messenger > group > Group


1 /**
2  * $RCSfile: Group.java,v $
3  * $Revision: 1.20 $
4  * $Date: 2005/07/25 20:33:15 $
5  *
6  * Copyright (C) 2004 Jive Software. All rights reserved.
7  *
8  * This software is published under the terms of the GNU Public License (GPL),
9  * a copy of which is included in this distribution.
10  */

11
12 package org.jivesoftware.messenger.group;
13
14 import org.jivesoftware.util.Log;
15 import org.jivesoftware.util.Cacheable;
16 import org.jivesoftware.util.CacheSizes;
17 import org.jivesoftware.database.DbConnectionManager;
18 import org.jivesoftware.messenger.event.GroupEventDispatcher;
19 import org.jivesoftware.messenger.user.UserManager;
20 import org.jivesoftware.stringprep.Stringprep;
21
22 import java.util.*;
23 import java.util.concurrent.ConcurrentHashMap JavaDoc;
24 import java.sql.Connection JavaDoc;
25 import java.sql.PreparedStatement JavaDoc;
26 import java.sql.ResultSet JavaDoc;
27 import java.sql.SQLException JavaDoc;
28
29 /**
30  * Groups organize users into a single entity for easier management.
31  *
32  * @see GroupManager#createGroup(String)
33  *
34  * @author Matt Tucker
35  */

36 public class Group implements Cacheable {
37
38     private static final String JavaDoc LOAD_PROPERTIES =
39         "SELECT name, propValue FROM jiveGroupProp WHERE groupName=?";
40     private static final String JavaDoc DELETE_PROPERTY =
41         "DELETE FROM jiveGroupProp WHERE groupName=? AND name=?";
42     private static final String JavaDoc UPDATE_PROPERTY =
43         "UPDATE jiveGroupProp SET propValue=? WHERE name=? AND groupName=?";
44     private static final String JavaDoc INSERT_PROPERTY =
45         "INSERT INTO jiveGroupProp (groupName, name, propValue) VALUES (?, ?, ?)";
46
47     private GroupProvider provider;
48     private GroupManager groupManager;
49     private String JavaDoc name;
50     private String JavaDoc description;
51     private Map JavaDoc<String JavaDoc, String JavaDoc> properties;
52     private Collection<String JavaDoc> members;
53     private Collection<String JavaDoc> administrators;
54
55     /**
56      * Constructs a new group. Note: this constructor is intended for implementors of the
57      * {@link GroupProvider} interface. To create a new group, use the
58      * {@link GroupManager#createGroup(String)} method.
59      *
60      * @param provider the group provider.
61      * @param name the name.
62      * @param description the description.
63      * @param members a Collection of the group members.
64      * @param administrators a Collection of the group administrators.
65      */

66     public Group(GroupProvider provider, String JavaDoc name, String JavaDoc description,
67             Collection<String JavaDoc> members, Collection<String JavaDoc> administrators)
68     {
69         this.provider = provider;
70         this.groupManager = GroupManager.getInstance();
71         this.name = name;
72         this.description = description;
73         this.members = members;
74         this.administrators = administrators;
75     }
76
77     /**
78      * Returns the name of the group. For example, 'XYZ Admins'.
79      *
80      * @return the name of the group.
81      */

82     public String JavaDoc getName() {
83         return name;
84     }
85
86     /**
87      * Sets the name of the group. For example, 'XYZ Admins'. This
88      * method is restricted to those with group administration permission.
89      *
90      * @param name the name for the group.
91      */

92     public void setName(String JavaDoc name) {
93         try {
94             String JavaDoc originalName = this.name;
95             provider.setName(this.name, name);
96             groupManager.groupCache.remove(this.name);
97             this.name = name;
98             groupManager.groupCache.put(name, this);
99
100             // Fire event.
101
Map JavaDoc<String JavaDoc, Object JavaDoc> params = new HashMap JavaDoc<String JavaDoc, Object JavaDoc>();
102             params.put("type", "nameModified");
103             params.put("originalValue", originalName);
104             GroupEventDispatcher.dispatchEvent(this, GroupEventDispatcher.EventType.group_modified,
105                     params);
106         }
107         catch (Exception JavaDoc e) {
108             Log.error(e);
109         }
110     }
111
112     /**
113      * Returns the description of the group. The description often
114      * summarizes a group's function, such as 'Administrators of the XYZ forum'.
115      *
116      * @return the description of the group.
117      */

118     public String JavaDoc getDescription() {
119         return description;
120     }
121
122     /**
123      * Sets the description of the group. The description often
124      * summarizes a group's function, such as 'Administrators of
125      * the XYZ forum'. This method is restricted to those with group
126      * administration permission.
127      *
128      * @param description the description of the group.
129      */

130     public void setDescription(String JavaDoc description) {
131         try {
132             String JavaDoc originalDescription = this.description;
133             provider.setDescription(name, description);
134             this.description = description;
135             // Fire event.
136
Map JavaDoc<String JavaDoc, Object JavaDoc> params = new HashMap JavaDoc<String JavaDoc, Object JavaDoc>();
137             params.put("type", "descriptionModified");
138             params.put("originalValue", originalDescription);
139             GroupEventDispatcher.dispatchEvent(this,
140                     GroupEventDispatcher.EventType.group_modified, params);
141         }
142         catch (Exception JavaDoc e) {
143             Log.error(e);
144         }
145     }
146
147     /**
148      * Returns all extended properties of the group. Groups
149      * have an arbitrary number of extended properties.
150      *
151      * @return the extended properties.
152      */

153     public Map JavaDoc<String JavaDoc,String JavaDoc> getProperties() {
154         synchronized (this) {
155             if (properties == null) {
156                 properties = new ConcurrentHashMap JavaDoc<String JavaDoc, String JavaDoc>();
157                 loadProperties();
158             }
159         }
160         // Return a wrapper that will intercept add and remove commands.
161
return new PropertiesMap();
162     }
163
164     /**
165      * Returns a Collection of the group administrators.
166      *
167      * @return a Collection of the group administrators.
168      */

169     public Collection<String JavaDoc> getAdmins() {
170         // Return a wrapper that will intercept add and remove commands.
171
return new MemberCollection(administrators, true);
172     }
173
174     /**
175      * Returns a Collection of the group members.
176      *
177      * @return a Collection of the group members.
178      */

179     public Collection<String JavaDoc> getMembers() {
180         // Return a wrapper that will intercept add and remove commands.
181
return new MemberCollection(members, false);
182     }
183
184     /**
185      * Returns true if the provided username belongs to a user of the group.
186      *
187      * @param username the username to check.
188      * @return true if the provided username belongs to a user of the group.
189      */

190     public boolean isUser(String JavaDoc username) {
191         return members.contains(username) || administrators.contains(username);
192     }
193
194     public int getCachedSize() {
195         // Approximate the size of the object in bytes by calculating the size
196
// of each field.
197
int size = 0;
198         size += CacheSizes.sizeOfObject(); // overhead of object
199
size += CacheSizes.sizeOfString(name);
200         size += CacheSizes.sizeOfString(description);
201         return size;
202     }
203
204     /**
205      * Collection implementation that notifies the GroupProvider of any
206      * changes to the collection.
207      */

208     private class MemberCollection extends AbstractCollection {
209
210         private Collection<String JavaDoc> users;
211         private boolean adminCollection;
212
213         public MemberCollection(Collection<String JavaDoc> users, boolean adminCollection) {
214             this.users = users;
215             this.adminCollection = adminCollection;
216         }
217
218         public Iterator iterator() {
219             return new Iterator() {
220
221                 Iterator iter = users.iterator();
222                 Object JavaDoc current = null;
223
224                 public boolean hasNext() {
225                     return iter.hasNext();
226                 }
227
228                 public Object JavaDoc next() {
229                     current = iter.next();
230                     return current;
231                 }
232
233                 public void remove() {
234                     if (current == null) {
235                         throw new IllegalStateException JavaDoc();
236                     }
237                     String JavaDoc user = (String JavaDoc)current;
238                     // Remove the user from the collection in memory.
239
iter.remove();
240                     // Remove the group user from the backend store.
241
provider.deleteMember(name, user);
242                     // Fire event.
243
if (adminCollection) {
244                         Map JavaDoc<String JavaDoc, String JavaDoc> params = new HashMap JavaDoc<String JavaDoc, String JavaDoc>();
245                         params.put("admin", user);
246                         GroupEventDispatcher.dispatchEvent(Group.this,
247                                 GroupEventDispatcher.EventType.admin_removed, params);
248                     }
249                     else {
250                         Map JavaDoc<String JavaDoc, String JavaDoc> params = new HashMap JavaDoc<String JavaDoc, String JavaDoc>();
251                         params.put("member", user);
252                         GroupEventDispatcher.dispatchEvent(Group.this,
253                                 GroupEventDispatcher.EventType.member_removed, params);
254                     }
255                 }
256             };
257         }
258
259         public int size() {
260             return users.size();
261         }
262
263         public boolean add(Object JavaDoc member) {
264             String JavaDoc username = (String JavaDoc) member;
265             try {
266                 username = Stringprep.nodeprep(username);
267                 UserManager.getInstance().getUser(username);
268             }
269             catch (Exception JavaDoc e) {
270                 throw new IllegalArgumentException JavaDoc("Invalid user.", e);
271             }
272             // Find out if the user was already a group user
273
boolean alreadyGroupUser = false;
274             if (adminCollection) {
275                 alreadyGroupUser = members.contains(username);
276             }
277             else {
278                 alreadyGroupUser = administrators.contains(username);
279             }
280             if (users.add(username)) {
281                 if (alreadyGroupUser) {
282                     // Update the group user privileges in the backend store.
283
provider.updateMember(name, username, adminCollection);
284                 }
285                 else {
286                     // Add the group user to the backend store.
287
provider.addMember(name, username, adminCollection);
288                 }
289
290                 // Fire event.
291
if (adminCollection) {
292                     Map JavaDoc<String JavaDoc, String JavaDoc> params = new HashMap JavaDoc<String JavaDoc, String JavaDoc>();
293                     params.put("admin", username);
294                     if (alreadyGroupUser) {
295                         GroupEventDispatcher.dispatchEvent(Group.this,
296                                     GroupEventDispatcher.EventType.member_removed, params);
297                     }
298                     GroupEventDispatcher.dispatchEvent(Group.this,
299                                 GroupEventDispatcher.EventType.admin_added, params);
300                 }
301                 else {
302                     Map JavaDoc<String JavaDoc, String JavaDoc> params = new HashMap JavaDoc<String JavaDoc, String JavaDoc>();
303                     params.put("member", username);
304                     if (alreadyGroupUser) {
305                         GroupEventDispatcher.dispatchEvent(Group.this,
306                                     GroupEventDispatcher.EventType.admin_removed, params);
307                     }
308                     GroupEventDispatcher.dispatchEvent(Group.this,
309                                 GroupEventDispatcher.EventType.member_added, params);
310                 }
311                 // If the user was a member that became an admin or vice versa then remove the
312
// user from the other collection
313
if (alreadyGroupUser) {
314                     if (adminCollection) {
315                         if (members.contains(username)) {
316                             members.remove(username);
317                         }
318                     }
319                     else {
320                         if (administrators.contains(username)) {
321                             administrators.remove(username);
322                         }
323                     }
324                 }
325                 return true;
326             }
327             return false;
328         }
329     }
330
331     /**
332      * Map implementation that updates the database when properties are modified.
333      */

334     private class PropertiesMap extends AbstractMap {
335
336         public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
337             if (key == null || value == null) {
338                 throw new NullPointerException JavaDoc();
339             }
340             Map JavaDoc<String JavaDoc, Object JavaDoc> eventParams = new HashMap JavaDoc<String JavaDoc, Object JavaDoc>();
341             Object JavaDoc answer;
342             String JavaDoc keyString = (String JavaDoc) key;
343             synchronized (keyString.intern()) {
344                 if (properties.containsKey(keyString)) {
345                     String JavaDoc originalValue = properties.get(keyString);
346                     answer = properties.put(keyString, (String JavaDoc)value);
347                     updateProperty(keyString, (String JavaDoc)value);
348                     // Configure event.
349
eventParams.put("type", "propertyModified");
350                     eventParams.put("propertyKey", key);
351                     eventParams.put("originalValue", originalValue);
352                 }
353                 else {
354                     answer = properties.put(keyString, (String JavaDoc)value);
355                     insertProperty(keyString, (String JavaDoc)value);
356                     // Configure event.
357
eventParams.put("type", "propertyAdded");
358                     eventParams.put("propertyKey", key);
359                 }
360             }
361             // Fire event.
362
GroupEventDispatcher.dispatchEvent(Group.this,
363                     GroupEventDispatcher.EventType.group_modified, eventParams);
364             return answer;
365         }
366
367         public Set JavaDoc<Entry> entrySet() {
368             return new PropertiesEntrySet();
369         }
370     }
371
372     /**
373      * Set implementation that updates the database when properties are deleted.
374      */

375     private class PropertiesEntrySet extends AbstractSet {
376
377         public int size() {
378             return properties.entrySet().size();
379         }
380
381         public Iterator iterator() {
382             return new Iterator() {
383
384                 Iterator iter = properties.entrySet().iterator();
385                 Map.Entry JavaDoc current = null;
386
387                 public boolean hasNext() {
388                     return iter.hasNext();
389                 }
390
391                 public Object JavaDoc next() {
392                     current = (Map.Entry JavaDoc)iter.next();
393                     return current;
394                 }
395
396                 public void remove() {
397                     if (current == null) {
398                         throw new IllegalStateException JavaDoc();
399                     }
400                     String JavaDoc key = (String JavaDoc)current.getKey();
401                     deleteProperty(key);
402                     iter.remove();
403                     // Fire event.
404
Map JavaDoc<String JavaDoc, Object JavaDoc> params = new HashMap JavaDoc<String JavaDoc, Object JavaDoc>();
405                     params.put("type", "propertyDeleted");
406                     params.put("propertyKey", key);
407                     GroupEventDispatcher.dispatchEvent(Group.this,
408                         GroupEventDispatcher.EventType.group_modified, params);
409                 }
410             };
411         }
412     }
413
414     private void loadProperties() {
415         Connection JavaDoc con = null;
416         PreparedStatement JavaDoc pstmt = null;
417         try {
418             con = DbConnectionManager.getConnection();
419             pstmt = con.prepareStatement(LOAD_PROPERTIES);
420             pstmt.setString(1, name);
421             ResultSet JavaDoc rs = pstmt.executeQuery();
422             while (rs.next()) {
423                 properties.put(rs.getString(1), rs.getString(2));
424             }
425             rs.close();
426         }
427         catch (SQLException JavaDoc sqle) {
428             Log.error(sqle);
429         }
430         finally {
431             try { if (pstmt != null) pstmt.close(); }
432             catch (Exception JavaDoc e) { Log.error(e); }
433             try { if (con != null) con.close(); }
434             catch (Exception JavaDoc e) { Log.error(e); }
435         }
436     }
437
438     private void insertProperty(String JavaDoc propName, String JavaDoc propValue) {
439         Connection JavaDoc con = null;
440         PreparedStatement JavaDoc pstmt = null;
441         try {
442             con = DbConnectionManager.getConnection();
443             pstmt = con.prepareStatement(INSERT_PROPERTY);
444             pstmt.setString(1, name);
445             pstmt.setString(2, propName);
446             pstmt.setString(3, propValue);
447             pstmt.executeUpdate();
448         }
449         catch (SQLException JavaDoc e) {
450             Log.error(e);
451         }
452         finally {
453             try { if (pstmt != null) pstmt.close(); }
454             catch (Exception JavaDoc e) { Log.error(e); }
455             try { if (con != null) con.close(); }
456             catch (Exception JavaDoc e) { Log.error(e); }
457         }
458     }
459
460     private void updateProperty(String JavaDoc propName, String JavaDoc propValue) {
461         Connection JavaDoc con = null;
462         PreparedStatement JavaDoc pstmt = null;
463         try {
464             con = DbConnectionManager.getConnection();
465             pstmt = con.prepareStatement(UPDATE_PROPERTY);
466             pstmt.setString(1, propValue);
467             pstmt.setString(2, propName);
468             pstmt.setString(3, name);
469             pstmt.executeUpdate();
470         }
471         catch (SQLException JavaDoc e) {
472             Log.error(e);
473         }
474         finally {
475             try { if (pstmt != null) pstmt.close(); }
476             catch (Exception JavaDoc e) { Log.error(e); }
477             try { if (con != null) con.close(); }
478             catch (Exception JavaDoc e) { Log.error(e); }
479         }
480     }
481
482     private void deleteProperty(String JavaDoc propName) {
483         Connection JavaDoc con = null;
484         PreparedStatement JavaDoc pstmt = null;
485         try {
486             con = DbConnectionManager.getConnection();
487             pstmt = con.prepareStatement(DELETE_PROPERTY);
488             pstmt.setString(1, name);
489             pstmt.setString(2, propName);
490             pstmt.executeUpdate();
491         }
492         catch (SQLException JavaDoc e) {
493             Log.error(e);
494         }
495         finally {
496             try { if (pstmt != null) pstmt.close(); }
497             catch (Exception JavaDoc e) { Log.error(e); }
498             try { if (con != null) con.close(); }
499             catch (Exception JavaDoc e) { Log.error(e); }
500         }
501     }
502 }
Popular Tags