001: /* Copyright 2001, 2002 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal.groups;
007:
008: import java.util.ArrayList;
009: import java.util.Collection;
010: import java.util.HashSet;
011: import java.util.Iterator;
012: import java.util.Set;
013:
014: import org.jasig.portal.EntityIdentifier;
015: import org.jasig.portal.services.GroupService;
016:
017: /**
018: * GroupMemberImpl summary first sentence goes here.
019: *
020: * @author Dan Ellentuck
021: * @version $Revision: 36806 $
022: * @see IGroupMember
023: */
024: public abstract class GroupMemberImpl implements IGroupMember {
025: /*
026: * The <code>EntityIdentifier</code> that uniquely identifies the entity,
027: * e.g., the <code>IPerson</code>, <code>ChannelDefinition</code>, etc.,
028: * that underlies the <code>IGroupMember</code>.
029: */
030: private EntityIdentifier underlyingEntityIdentifier;
031: private static java.lang.Class defaultEntityType;
032:
033: /*
034: * The Set of keys to groups that contain this <code>IGroupMember</code>.
035: * the groups themselves are cached by the service.
036: */
037: private Set groupKeys;
038: private boolean groupKeysInitialized;
039:
040: /**
041: * GroupMemberImpl constructor
042: */
043: public GroupMemberImpl(String key, Class type)
044: throws GroupsException {
045: this (new EntityIdentifier(key, type));
046: }
047:
048: /**
049: * GroupMemberImpl constructor
050: */
051: public GroupMemberImpl(EntityIdentifier newEntityIdentifier)
052: throws GroupsException {
053: super ();
054: if (isKnownEntityType(newEntityIdentifier.getType())) {
055: underlyingEntityIdentifier = newEntityIdentifier;
056: } else {
057: throw new GroupsException("Unknown entity type: "
058: + newEntityIdentifier.getType());
059: }
060: }
061:
062: /**
063: * Adds the key of the <code>IEntityGroup</code> to our <code>Set</code> of group keys
064: * by copying the keys, updating the copy, and replacing the old keys with the copy.
065: * This lets us confine synchronization to the getter and setter methods for the keys.
066: * @param eg org.jasig.portal.groups.IEntityGroup
067: */
068: public void addGroup(IEntityGroup eg) throws GroupsException {
069: Set newGroupKeys = copyGroupKeys();
070: newGroupKeys.add(eg.getEntityIdentifier().getKey());
071: setGroupKeys(newGroupKeys);
072: }
073:
074: /**
075: * @return boolean
076: */
077: private boolean areGroupKeysInitialized() {
078: return groupKeysInitialized;
079: }
080:
081: /**
082: * Default implementation, overridden on EntityGroupImpl.
083: * @param gm org.jasig.portal.groups.IGroupMember
084: * @return boolean
085: */
086: public boolean contains(IGroupMember gm) throws GroupsException {
087: return false;
088: }
089:
090: /**
091: * Clone the group keys.
092: * @return Set
093: */
094: private Set copyGroupKeys() throws GroupsException {
095: return castAndCopyHashSet(getGroupKeys());
096: }
097:
098: /**
099: * Cast a Set to a HashSet, clone it, and down cast back to Set.
100: * @return HashSet
101: */
102: protected Set castAndCopyHashSet(Set s) {
103: return (Set) ((HashSet) s).clone();
104: }
105:
106: /**
107: * Default implementation, overridden on EntityGroupImpl.
108: * @param gm org.jasig.portal.groups.IGroupMember
109: * @return boolean
110: */
111: public boolean deepContains(IGroupMember gm) throws GroupsException {
112: return false;
113: }
114:
115: /**
116: * Returns an <code>Iterator</code> over the <code>Set</code> of this
117: * <code>IGroupMember's</code> recursively-retrieved parent groups.
118: *
119: * @return java.util.Iterator
120: */
121: public java.util.Iterator getAllContainingGroups()
122: throws GroupsException {
123: return primGetAllContainingGroups(this , new HashSet())
124: .iterator();
125: }
126:
127: /**
128: * Default implementation, overridden on EntityGroupImpl.
129: * @return java.util.Iterator
130: */
131: public java.util.Iterator getAllEntities() throws GroupsException {
132: return getEmptyIterator();
133: }
134:
135: /**
136: * Default implementation, overridden on EntityGroupImpl.
137: * @return java.util.Iterator
138: */
139: public java.util.Iterator getAllMembers() throws GroupsException {
140: return getEmptyIterator();
141: }
142:
143: /**
144: * @return java.lang.String
145: */
146: protected String getCacheKey() {
147: return getEntityIdentifier().getKey();
148: }
149:
150: /**
151: * Returns the composite group service.
152: */
153: protected ICompositeGroupService getCompositeGroupService()
154: throws GroupsException {
155: return GroupService.getCompositeGroupService();
156: }
157:
158: /**
159: * Returns an <code>Iterator</code> over this <code>IGroupMember's</code> parent groups.
160: * Synchronize the collection of keys with adds and removes.
161: * @return java.util.Iterator
162: */
163: public java.util.Iterator getContainingGroups()
164: throws GroupsException {
165: Collection groupsColl;
166:
167: Set groupKeys = getGroupKeys();
168: groupsColl = new ArrayList(groupKeys.size());
169: for (Iterator itr = groupKeys.iterator(); itr.hasNext();) {
170: String groupKey = (String) itr.next();
171: groupsColl.add(getCompositeGroupService().findGroup(
172: groupKey));
173: }
174:
175: return groupsColl.iterator();
176: }
177:
178: /**
179: * @return java.lang.Class
180: */
181: private java.lang.Class getDefaultEntityType() {
182: if (defaultEntityType == null) {
183: Class cls = (new Object()).getClass();
184: defaultEntityType = cls;
185: }
186: return defaultEntityType;
187: }
188:
189: /**
190: * @return java.util.Iterator
191: */
192: private java.util.Iterator getEmptyIterator() {
193: return java.util.Collections.EMPTY_LIST.iterator();
194: }
195:
196: /**
197: * Default implementation, overridden on EntityGroupImpl.
198: * @return java.util.Iterator
199: */
200: public java.util.Iterator getEntities() throws GroupsException {
201: return getEmptyIterator();
202: }
203:
204: /**
205: * @return java.util.Set
206: */
207: private synchronized java.util.Set getGroupKeys()
208: throws GroupsException {
209: if (!groupKeysInitialized) {
210: initializeContainingGroupKeys();
211: }
212: return groupKeys;
213: }
214:
215: /**
216: * @return java.lang.String
217: */
218: public java.lang.String getKey() {
219: return getUnderlyingEntityIdentifier().getKey();
220: }
221:
222: /**
223: * Default implementation, overridden on EntityGroupImpl.
224: * @return org.jasig.portal.groups.IEntityGroup
225: * @param name java.lang.String
226: */
227: public IEntityGroup getMemberGroupNamed(String name)
228: throws GroupsException {
229: return null;
230: }
231:
232: /**
233: * Default implementation, overridden on EntityGroupImpl.
234: * @return java.util.Iterator
235: */
236: public java.util.Iterator getMembers() throws GroupsException {
237: return getEmptyIterator();
238: }
239:
240: /**
241: * @return java.lang.Class
242: */
243: public java.lang.Class getType() {
244: return getUnderlyingEntityIdentifier().getType();
245: }
246:
247: /**
248: * @return EntityIdentifier
249: */
250: public EntityIdentifier getUnderlyingEntityIdentifier() {
251: return underlyingEntityIdentifier;
252: }
253:
254: /*
255: * @return an integer hash code for the receiver
256: * @see java.util.Hashtable
257: */
258: public int hashCode() {
259: return getKey().hashCode();
260: }
261:
262: /**
263: * Default implementation, overridden on EntityGroupImpl.
264: * @return boolean
265: */
266: public boolean hasMembers() throws GroupsException {
267: return false;
268: }
269:
270: /**
271: * Cache the keys for <code>IEntityGroups</code> that contain this <code>IGroupMember</code>.
272: */
273: private void initializeContainingGroupKeys() throws GroupsException {
274: Set keys = new HashSet(10);
275: for (Iterator it = getCompositeGroupService()
276: .findContainingGroups(this ); it.hasNext();) {
277: IEntityGroup eg = (IEntityGroup) it.next();
278: keys.add(eg.getEntityIdentifier().getKey());
279: }
280: setGroupKeys(keys);
281: setGroupKeysInitialized(true);
282: }
283:
284: /**
285: * Answers if this <code>IGroupMember</code> is, recursively, a member of <code>IGroupMember</code> gm.
286: * @return boolean
287: * @param gm org.jasig.portal.groups.IGroupMember
288: */
289: public boolean isDeepMemberOf(IGroupMember gm)
290: throws GroupsException {
291:
292: if (this .isMemberOf(gm)) {
293: return true;
294: }
295: return gm.deepContains(this );
296: }
297:
298: /**
299: * @return boolean
300: */
301: public boolean isEntity() {
302: return false;
303: }
304:
305: /**
306: * @return boolean
307: */
308: public boolean isGroup() {
309: return false;
310: }
311:
312: /**
313: * @return boolean.
314: */
315: protected boolean isKnownEntityType(Class anEntityType)
316: throws GroupsException {
317: return (org.jasig.portal.EntityTypes
318: .getEntityTypeID(anEntityType) != null);
319: }
320:
321: /**
322: * Answers if this <code>IGroupMember</code> is a member of <code>IGroupMember</code> gm.
323: * @param gm org.jasig.portal.groups.IGroupMember
324: * @return boolean
325: */
326: public boolean isMemberOf(IGroupMember gm) throws GroupsException {
327: if (gm == this || gm.isEntity()) {
328: return false;
329: }
330: Object cacheKey = gm.getKey();
331: return getGroupKeys().contains(cacheKey);
332: }
333:
334: /**
335: * Returns the <code>Set</code> of groups in our member <code>Collection</code> and,
336: * recursively, in the <code>Collections</code> of our members.
337: * @param member org.jasig.portal.groups.IGroupMember - The current group member in the recursive execution.
338: * @param s java.lang.Set - A Set that groups are added to.
339: * @return java.util.Set
340: */
341: protected java.util.Set primGetAllContainingGroups(
342: IGroupMember member, Set s) throws GroupsException {
343: Iterator i = member.getContainingGroups();
344: while (i.hasNext()) {
345: IGroupMember gm = (IGroupMember) i.next();
346: s.add(gm);
347: primGetAllContainingGroups(gm, s);
348: }
349: return s;
350: }
351:
352: /**
353: * Removes the key of the <code>IEntityGroup</code> from our <code>Set</code> of group keys
354: * by copying the keys, updating the copy, and replacing the old keys with the copy.
355: * This lets us confine synchronization to the getter and setter methods for the keys.
356: * @param eg org.jasig.portal.groups.IEntityGroup
357: */
358: public void removeGroup(IEntityGroup eg) throws GroupsException {
359: Set newGroupKeys = copyGroupKeys();
360: newGroupKeys.remove(eg.getEntityIdentifier().getKey());
361: setGroupKeys(newGroupKeys);
362: }
363:
364: /**
365: * @param newGroupKeys Set
366: */
367: private synchronized void setGroupKeys(Set newGroupKeys) {
368: groupKeys = newGroupKeys;
369: }
370:
371: /**
372: * @param newGroupKeysInitialized boolean
373: */
374: protected void setGroupKeysInitialized(
375: boolean newGroupKeysInitialized) {
376: groupKeysInitialized = newGroupKeysInitialized;
377: }
378: }
|