001: /* Copyright 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.ldap;
007:
008: import java.io.IOException;
009: import java.util.ArrayList;
010: import java.util.HashMap;
011: import java.util.Hashtable;
012: import java.util.Iterator;
013: import java.util.List;
014:
015: import javax.naming.Context;
016: import javax.naming.NamingEnumeration;
017: import javax.naming.NamingException;
018: import javax.naming.directory.Attribute;
019: import javax.naming.directory.Attributes;
020: import javax.naming.directory.BasicAttributes;
021: import javax.naming.directory.DirContext;
022: import javax.naming.directory.InitialDirContext;
023: import javax.naming.directory.SearchControls;
024: import javax.naming.directory.SearchResult;
025: import javax.xml.parsers.ParserConfigurationException;
026:
027: import org.jasig.portal.EntityIdentifier;
028: import org.jasig.portal.ResourceMissingException;
029: import org.jasig.portal.groups.EntityGroupImpl;
030: import org.jasig.portal.groups.EntityImpl;
031: import org.jasig.portal.groups.GroupsException;
032: import org.jasig.portal.groups.IEntity;
033: import org.jasig.portal.groups.IEntityGroup;
034: import org.jasig.portal.groups.IEntityGroupStore;
035: import org.jasig.portal.groups.IEntitySearcher;
036: import org.jasig.portal.groups.IEntityStore;
037: import org.jasig.portal.groups.IGroupMember;
038: import org.jasig.portal.groups.ILockableEntityGroup;
039: import org.apache.commons.logging.Log;
040: import org.apache.commons.logging.LogFactory;
041: import org.jasig.portal.utils.ResourceLoader;
042: import org.jasig.portal.utils.SmartCache;
043: import org.w3c.dom.Document;
044: import org.w3c.dom.Element;
045: import org.w3c.dom.Node;
046: import org.w3c.dom.NodeList;
047: import org.w3c.dom.Text;
048: import org.xml.sax.SAXException;
049:
050: /**
051: * LDAPGroupStore.
052: * @author Alex Vidgor
053: * @version $Revision: 36810 $
054: */
055: public class LDAPGroupStore implements IEntityGroupStore, IEntityStore,
056: IEntitySearcher {
057: private static final Log log = LogFactory
058: .getLog(LDAPGroupStore.class);
059: protected String url;
060: protected String logonid;
061: protected String logonpassword;
062: protected String keyfield;
063: protected String namefield;
064: protected String usercontext = "";
065: protected HashMap groups;
066: protected SmartCache contexts;
067: protected SmartCache personkeys;
068: protected static Class iperson = org.jasig.portal.security.IPerson.class;
069: protected static Class group = org.jasig.portal.groups.IEntityGroup.class;
070: protected static short ELEMENT_NODE = Node.ELEMENT_NODE;
071:
072: public LDAPGroupStore() {
073: Document config = null;
074: try {
075: config = ResourceLoader.getResourceAsDocument(this
076: .getClass(),
077: "/properties/groups/LDAPGroupStoreConfig.xml");
078: } catch (IOException e) {
079: throw new RuntimeException(
080: "LDAPGroupStore: Unable to find configuration configuration document",
081: e);
082: } catch (ResourceMissingException e) {
083: throw new RuntimeException(
084: "LDAPGroupStore: Unable to find configuration configuration document",
085: e);
086: } catch (ParserConfigurationException e) {
087: throw new RuntimeException(
088: "LDAPGroupStore: Unable to find configuration configuration document",
089: e);
090: } catch (SAXException e) {
091: throw new RuntimeException(
092: "LDAPGroupStore: Unable to find configuration configuration document",
093: e);
094: }
095: init(config);
096: }
097:
098: public LDAPGroupStore(Document config) {
099: init(config);
100: }
101:
102: protected void init(Document config) {
103: this .groups = new HashMap();
104: this .contexts = new SmartCache(120);
105: config.normalize();
106: int refreshminutes = 120;
107: Element root = config.getDocumentElement();
108: NodeList nl = root.getElementsByTagName("config");
109: if (nl.getLength() == 1) {
110: Element conf = (Element) nl.item(0);
111: Node cc = conf.getFirstChild();
112: //NodeList cl= conf.getF.getChildNodes();
113: //for(int i=0; i<cl.getLength(); i++){
114: while (cc != null) {
115: if (cc.getNodeType() == ELEMENT_NODE) {
116: Element c = (Element) cc;
117: c.normalize();
118: Node t = c.getFirstChild();
119: if (t != null && t.getNodeType() == Node.TEXT_NODE) {
120: String name = c.getNodeName();
121: String text = ((Text) t).getData();
122: //System.out.println(name+" = "+text);
123: if (name.equals("url")) {
124: url = text;
125: } else if (name.equals("logonid")) {
126: logonid = text;
127: } else if (name.equals("logonpassword")) {
128: logonpassword = text;
129: } else if (name.equals("keyfield")) {
130: keyfield = text;
131: } else if (name.equals("namefield")) {
132: namefield = text;
133: } else if (name.equals("usercontext")) {
134: usercontext = text;
135: } else if (name.equals("refresh-minutes")) {
136: try {
137: refreshminutes = Integer.parseInt(text);
138: } catch (Exception e) {
139: }
140: }
141: }
142: }
143: cc = cc.getNextSibling();
144: }
145: } else {
146: throw new RuntimeException(
147: "LDAPGroupStore: config file must contain one config element");
148: }
149:
150: this .personkeys = new SmartCache(refreshminutes * 60);
151:
152: NodeList gl = root.getChildNodes();
153: for (int j = 0; j < gl.getLength(); j++) {
154: if (gl.item(j).getNodeType() == ELEMENT_NODE) {
155: Element g = (Element) gl.item(j);
156: if (g.getNodeName().equals("group")) {
157: GroupShadow shadow = processXmlGroupRecursive(g);
158: groups.put(shadow.key, shadow);
159: }
160: }
161: }
162:
163: }
164:
165: protected String[] getPersonKeys(String groupKey) {
166: String[] r = (String[]) personkeys.get(groupKey);
167: if (r == null) {
168: GroupShadow shadow = (GroupShadow) groups.get(groupKey);
169: if (shadow.entities != null) {
170: r = shadow.entities.getPersonKeys();
171: } else {
172: r = new String[0];
173: }
174: personkeys.put(groupKey, r);
175: }
176: return r;
177: }
178:
179: protected GroupShadow processXmlGroupRecursive(Element groupElem) {
180: GroupShadow shadow = new GroupShadow();
181: shadow.key = groupElem.getAttribute("key");
182: shadow.name = groupElem.getAttribute("name");
183: //System.out.println("Loading configuration for group "+shadow.name);
184: ArrayList subgroups = new ArrayList();
185: NodeList nl = groupElem.getChildNodes();
186: for (int i = 0; i < nl.getLength(); i++) {
187: if (nl.item(i).getNodeType() == ELEMENT_NODE) {
188: Element e = (Element) nl.item(i);
189: if (e.getNodeName().equals("group")) {
190: GroupShadow sub = processXmlGroupRecursive(e);
191: subgroups.add(sub);
192: groups.put(sub.key, sub);
193: } else if (e.getNodeName().equals("entity-set")) {
194: shadow.entities = new EntitySet(e);
195: } else if (e.getNodeName().equals("description")) {
196: e.normalize();
197: Text t = (Text) e.getFirstChild();
198: if (t != null) {
199: shadow.description = t.getData();
200: }
201: }
202: }
203: }
204: shadow.subgroups = (GroupShadow[]) subgroups
205: .toArray(new GroupShadow[0]);
206: return shadow;
207: }
208:
209: protected class GroupShadow {
210: protected String key;
211: protected String name;
212: protected String description;
213: protected GroupShadow[] subgroups;
214: protected EntitySet entities;
215: }
216:
217: protected class EntitySet {
218: public static final int FILTER = 1;
219: public static final int UNION = 2;
220: public static final int DIFFERENCE = 3;
221: public static final int INTERSECTION = 4;
222: public static final int SUBTRACT = 5;
223: public static final int ATTRIBUTES = 6;
224:
225: protected int type;
226: protected String filter;
227: protected Attributes attributes;
228: protected EntitySet[] subsets;
229:
230: protected EntitySet(Element entityset) {
231: entityset.normalize();
232: Node n = entityset.getFirstChild();
233: while (n.getNodeType() != Node.ELEMENT_NODE) {
234: n = n.getNextSibling();
235: }
236: Element e = (Element) n;
237: String type = e.getNodeName();
238: boolean collectSubsets = false;
239: if (type.equals("filter")) {
240: this .type = FILTER;
241: filter = e.getAttribute("string");
242: } else if (type.equals("attributes")) {
243: this .type = ATTRIBUTES;
244: attributes = new BasicAttributes();
245: NodeList atts = e.getChildNodes();
246: for (int i = 0; i < atts.getLength(); i++) {
247: if (atts.item(i).getNodeType() == ELEMENT_NODE) {
248: Element a = (Element) atts.item(i);
249: attributes.put(a.getAttribute("name"), a
250: .getAttribute("value"));
251: }
252: }
253: } else if (type.equals("union")) {
254: this .type = UNION;
255: collectSubsets = true;
256: } else if (type.equals("intersection")) {
257: this .type = INTERSECTION;
258: collectSubsets = true;
259: } else if (type.equals("difference")) {
260: this .type = DIFFERENCE;
261: collectSubsets = true;
262: } else if (type.equals("subtract")) {
263: this .type = SUBTRACT;
264: collectSubsets = true;
265: }
266:
267: if (collectSubsets) {
268: ArrayList subs = new ArrayList();
269: NodeList nl = e.getChildNodes();
270: for (int i = 0; i < nl.getLength(); i++) {
271: if (nl.item(i).getNodeType() == Node.ELEMENT_NODE) {
272: EntitySet subset = new EntitySet((Element) nl
273: .item(i));
274: subs.add(subset);
275: }
276: }
277: subsets = (EntitySet[]) subs.toArray(new EntitySet[0]);
278: }
279: }
280:
281: protected String[] getPersonKeys() {
282: ArrayList keys = new ArrayList();
283: //System.out.println("Loading keys!!");
284: String[] subkeys;
285: switch (type) {
286: case FILTER:
287: //System.out.println("Performing ldap query!!");
288: DirContext context = getConnection();
289: NamingEnumeration userlist = null;
290: SearchControls sc = new SearchControls();
291: sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
292: sc.setReturningAttributes(new String[] { keyfield });
293: try {
294: userlist = context.search(usercontext, filter, sc);
295: } catch (NamingException nex) {
296: log.error(
297: "LDAPGroupStore: Unable to perform filter "
298: + filter, nex);
299: }
300: processLdapResults(userlist, keys);
301: break;
302: case ATTRIBUTES:
303: //System.out.println("Performing ldap attribute query!!");
304: DirContext context2 = getConnection();
305: NamingEnumeration userlist2 = null;
306: try {
307: userlist2 = context2.search(usercontext,
308: attributes, new String[] { keyfield });
309: } catch (NamingException nex) {
310: log
311: .error(
312: "LDAPGroupStore: Unable to perform attribute search",
313: nex);
314: }
315: processLdapResults(userlist2, keys);
316: break;
317: case UNION:
318: for (int i = 0; i < subsets.length; i++) {
319: subkeys = subsets[i].getPersonKeys();
320: for (int j = 0; j < subkeys.length; j++) {
321: String key = subkeys[j];
322: if (!keys.contains(key)) {
323: keys.add(key);
324: }
325: }
326: }
327: break;
328: case INTERSECTION:
329: if (subsets.length > 0) {
330: // load initial keys from first entity set
331: String[] interkeys = subsets[0].getPersonKeys();
332: // now set non-recurring keys to null
333: for (int m = 1; m < subsets.length; m++) {
334: subkeys = subsets[m].getPersonKeys();
335: for (int n = 0; n < interkeys.length; n++) {
336: if (interkeys[n] != null) {
337: boolean remove = true;
338: for (int o = 0; o < subkeys.length; o++) {
339: if (subkeys[o].equals(interkeys[n])) {
340: // found a match, so far the intersection for this key is valid
341: remove = false;
342: break;
343: }
344: }
345: if (remove) {
346: interkeys[n] = null;
347: }
348: }
349: }
350: }
351: for (int p = 0; p < interkeys.length; p++) {
352: if (interkeys[p] != null) {
353: keys.add(interkeys[p]);
354: }
355: }
356: }
357: break;
358: case DIFFERENCE:
359: if (subsets.length > 0) {
360: ArrayList discardKeys = new ArrayList();
361: subkeys = subsets[0].getPersonKeys();
362: // load initial keys from first entity set
363: for (int q = 0; q < subkeys.length; q++) {
364: keys.add(subkeys[q]);
365: }
366: for (int r = 1; r < subsets.length; r++) {
367: subkeys = subsets[r].getPersonKeys();
368: for (int s = 0; s < subkeys.length; s++) {
369: String ky = subkeys[s];
370: if (keys.contains(ky)) {
371: keys.remove(ky);
372: discardKeys.add(ky);
373: } else {
374: if (!discardKeys.contains(ky)) {
375: keys.add(ky);
376: }
377: }
378: }
379: }
380:
381: }
382: break;
383: case SUBTRACT:
384: if (subsets.length > 0) {
385: subkeys = subsets[0].getPersonKeys();
386: // load initial keys from first entity set
387: for (int t = 0; t < subkeys.length; t++) {
388: keys.add(subkeys[t]);
389: }
390: for (int u = 1; u < subsets.length; u++) {
391: subkeys = subsets[u].getPersonKeys();
392: for (int v = 0; v < subkeys.length; v++) {
393: String kyy = subkeys[v];
394: if (keys.contains(kyy)) {
395: keys.remove(kyy);
396: }
397: }
398: }
399: }
400: break;
401: }
402: return (String[]) keys.toArray(new String[0]);
403: }
404: }
405:
406: protected void processLdapResults(NamingEnumeration results,
407: ArrayList keys) {
408: //long time1 = System.currentTimeMillis();
409: //long casting=0;
410: //long getting=0;
411: //long setting=0;
412: //long looping=0;
413: //long loop1=System.currentTimeMillis();
414: try {
415: while (results.hasMore()) {
416: //long loop2 = System.currentTimeMillis();
417: //long cast1=System.currentTimeMillis();
418: //looping=looping+loop2-loop1;
419: SearchResult result = (SearchResult) results.next();
420: //long cast2 = System.currentTimeMillis();
421: //long get1 = System.currentTimeMillis();
422: Attributes ldapattribs = result.getAttributes();
423: //long get2 = System.currentTimeMillis();
424: //long set1 = System.currentTimeMillis();
425: Attribute attrib = ldapattribs.get(keyfield);
426: if (attrib != null) {
427: keys
428: .add(String.valueOf(attrib.get())
429: .toLowerCase());
430: }
431: //long set2 = System.currentTimeMillis();
432: //loop1=System.currentTimeMillis();
433: //casting=casting+cast2-cast1;
434: //setting=setting+set2-set1;
435: //getting=getting+get2-get1;
436: }
437: } catch (NamingException nex) {
438: log.error("LDAPGroupStore: error processing results", nex);
439: } finally {
440: try {
441: results.close();
442: } catch (Exception e) {
443: }
444: }
445: //long time5 = System.currentTimeMillis();
446: //System.out.println("Result processing took "+(time5-time1)+": "+getting+" for getting, "
447: // +setting+" for setting, "+casting+" for casting, "+looping+" for looping,"
448: // +(time5-loop1)+" for closing");
449: }
450:
451: protected DirContext getConnection() {
452: //JNDI boilerplate to connect to an initial context
453: DirContext context = (DirContext) contexts.get("context");
454: if (context == null) {
455: Hashtable jndienv = new Hashtable();
456: jndienv.put(Context.INITIAL_CONTEXT_FACTORY,
457: "com.sun.jndi.ldap.LdapCtxFactory");
458: jndienv.put(Context.SECURITY_AUTHENTICATION, "simple");
459: if (url.startsWith("ldaps")) { // Handle SSL connections
460: String newurl = url.substring(0, 4) + url.substring(5);
461: jndienv.put(Context.SECURITY_PROTOCOL, "ssl");
462: jndienv.put(Context.PROVIDER_URL, newurl);
463: } else {
464: jndienv.put(Context.PROVIDER_URL, url);
465: }
466: if (logonid != null)
467: jndienv.put(Context.SECURITY_PRINCIPAL, logonid);
468: if (logonpassword != null)
469: jndienv
470: .put(Context.SECURITY_CREDENTIALS,
471: logonpassword);
472: try {
473: context = new InitialDirContext(jndienv);
474: } catch (NamingException nex) {
475: log.error("LDAPGroupStore: unable to get context", nex);
476: }
477: contexts.put("context", context);
478: }
479: return context;
480: }
481:
482: protected IEntityGroup makeGroup(GroupShadow shadow)
483: throws GroupsException {
484: IEntityGroup group = null;
485: if (shadow != null) {
486: group = new EntityGroupImpl(shadow.key, iperson);
487: group.setDescription(shadow.description);
488: group.setName(shadow.name);
489: }
490: return group;
491: }
492:
493: protected GroupShadow getShadow(IEntityGroup group) {
494: return (GroupShadow) groups.get(group.getLocalKey());
495: }
496:
497: public void delete(IEntityGroup group) throws GroupsException {
498: throw new java.lang.UnsupportedOperationException(
499: "LDAPGroupStore: Method delete() not supported.");
500: }
501:
502: public IEntityGroup find(String key) throws GroupsException {
503: return makeGroup((GroupShadow) this .groups.get(key));
504: }
505:
506: public Iterator findContainingGroups(IGroupMember gm)
507: throws GroupsException {
508: ArrayList al = new ArrayList();
509: String key;
510: GroupShadow[] shadows = getGroupShadows();
511: if (gm.isEntity()) {
512: key = gm.getKey();
513: for (int i = 0; i < shadows.length; i++) {
514: String[] keys = getPersonKeys(shadows[i].key);
515: for (int j = 0; j < keys.length; j++) {
516: if (keys[j].equals(key)) {
517: al.add(makeGroup(shadows[i]));
518: break;
519: }
520: }
521: }
522: }
523:
524: if (gm.isGroup()) {
525: key = ((IEntityGroup) gm).getLocalKey();
526: for (int i = 0; i < shadows.length; i++) {
527: for (int j = 0; j < shadows[i].subgroups.length; j++) {
528: if (shadows[i].subgroups[j].key.equals(key)) {
529: al.add(makeGroup(shadows[i]));
530: break;
531: }
532: }
533: }
534: }
535:
536: return al.iterator();
537: }
538:
539: public String[] findMemberGroupKeys(IEntityGroup group)
540: throws GroupsException {
541: List keys = new ArrayList();
542: for (Iterator itr = findMemberGroups(group); itr.hasNext();) {
543: IEntityGroup eg = (IEntityGroup) itr.next();
544: keys.add(eg.getKey());
545: }
546: return (String[]) keys.toArray(new String[keys.size()]);
547: }
548:
549: public Iterator findMemberGroups(IEntityGroup group)
550: throws GroupsException {
551: ArrayList al = new ArrayList();
552: GroupShadow shadow = getShadow(group);
553: for (int i = 0; i < shadow.subgroups.length; i++) {
554: al.add(makeGroup(shadow.subgroups[i]));
555: }
556: return al.iterator();
557: }
558:
559: public IEntityGroup newInstance(Class entityType)
560: throws GroupsException {
561: throw new java.lang.UnsupportedOperationException(
562: "LDAPGroupStore: Method newInstance() not supported");
563: }
564:
565: public void update(IEntityGroup group) throws GroupsException {
566: throw new java.lang.UnsupportedOperationException(
567: "LDAPGroupStore: Method update() not supported");
568: }
569:
570: public void updateMembers(IEntityGroup group)
571: throws GroupsException {
572: throw new java.lang.UnsupportedOperationException(
573: "LDAPGroupStore: Method updateMembers() not supported");
574: }
575:
576: public ILockableEntityGroup findLockable(String key)
577: throws GroupsException {
578: throw new java.lang.UnsupportedOperationException(
579: "LDAPGroupStore: Method findLockable() not supported");
580: }
581:
582: protected GroupShadow[] getGroupShadows() {
583: return (GroupShadow[]) groups.values().toArray(
584: new GroupShadow[0]);
585: }
586:
587: public EntityIdentifier[] searchForGroups(String query, int method,
588: Class leaftype) throws GroupsException {
589: ArrayList ids = new ArrayList();
590: GroupShadow[] g = getGroupShadows();
591: int i;
592: switch (method) {
593: case IS:
594: for (i = 0; i < g.length; i++) {
595: if (g[i].name.equalsIgnoreCase(query)) {
596: ids.add(new EntityIdentifier(g[i].key, group));
597: }
598: }
599: break;
600: case STARTS_WITH:
601: for (i = 0; i < g.length; i++) {
602: if (g[i].name.toUpperCase().startsWith(
603: query.toUpperCase())) {
604: ids.add(new EntityIdentifier(g[i].key, group));
605: }
606: }
607: break;
608: case ENDS_WITH:
609: for (i = 0; i < g.length; i++) {
610: if (g[i].name.toUpperCase().endsWith(
611: query.toUpperCase())) {
612: ids.add(new EntityIdentifier(g[i].key, group));
613: }
614: }
615: break;
616: case CONTAINS:
617: for (i = 0; i < g.length; i++) {
618: if (g[i].name.toUpperCase()
619: .indexOf(query.toUpperCase()) > -1) {
620: ids.add(new EntityIdentifier(g[i].key, group));
621: }
622: }
623: break;
624: }
625: return (EntityIdentifier[]) ids
626: .toArray(new EntityIdentifier[0]);
627: }
628:
629: public Iterator findEntitiesForGroup(IEntityGroup group)
630: throws GroupsException {
631: GroupShadow shadow = getShadow(group);
632: ArrayList al = new ArrayList();
633: String[] keys = getPersonKeys(shadow.key);
634: for (int i = 0; i < keys.length; i++) {
635: al.add(new EntityImpl(keys[i], iperson));
636: }
637: return al.iterator();
638: }
639:
640: public IEntity newInstance(String key) throws GroupsException {
641: return new EntityImpl(key, null);
642: }
643:
644: public IEntity newInstance(String key, Class type)
645: throws GroupsException {
646: if (org.jasig.portal.EntityTypes.getEntityTypeID(type) == null) {
647: throw new GroupsException("Invalid group type: " + type);
648: }
649: return new EntityImpl(key, type);
650: }
651:
652: public EntityIdentifier[] searchForEntities(String query,
653: int method, Class type) throws GroupsException {
654: if (type != group && type != iperson)
655: return new EntityIdentifier[0];
656: ArrayList ids = new ArrayList();
657: switch (method) {
658: case STARTS_WITH:
659: query = query + "*";
660: break;
661: case ENDS_WITH:
662: query = "*" + query;
663: break;
664: case CONTAINS:
665: query = "*" + query + "*";
666: break;
667: }
668: query = namefield + "=" + query;
669: DirContext context = getConnection();
670: NamingEnumeration userlist = null;
671: SearchControls sc = new SearchControls();
672: sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
673: sc.setReturningAttributes(new String[] { keyfield });
674: try {
675: userlist = context.search(usercontext, query, sc);
676: } catch (NamingException nex) {
677: log.error("LDAPGroupStore: Unable to perform filter "
678: + query, nex);
679: }
680: ArrayList keys = new ArrayList();
681: processLdapResults(userlist, keys);
682: String[] k = (String[]) keys.toArray(new String[0]);
683: for (int i = 0; i < k.length; i++) {
684: ids.add(new EntityIdentifier(k[i], iperson));
685: }
686: return (EntityIdentifier[]) ids
687: .toArray(new EntityIdentifier[0]);
688: }
689:
690: /**
691: * Answers if <code>group</code> contains <code>member</code>.
692: * @return boolean
693: * @param group org.jasig.portal.groups.IEntityGroup
694: * @param member org.jasig.portal.groups.IGroupMember
695: */
696: public boolean contains(IEntityGroup group, IGroupMember member)
697: throws GroupsException {
698: boolean found = false;
699: Iterator itr = (member.isGroup()) ? findMemberGroups(group)
700: : findEntitiesForGroup(group);
701: while (itr.hasNext() && !found) {
702: found = member.equals(itr.next());
703: }
704: return found;
705: }
706:
707: /**
708: * Answers if <code>group</code> contains a member group named
709: * <code>name</code>.
710: * @return boolean
711: * @param group org.jasig.portal.groups.IEntityGroup
712: * @param name java.lang.String
713: */
714: public boolean containsGroupNamed(IEntityGroup group, String name)
715: throws GroupsException {
716: boolean found = false;
717: Iterator itr = findMemberGroups(group);
718: while (itr.hasNext() && !found) {
719: String otherName = ((IEntityGroup) itr.next()).getName();
720: found = otherName != null && otherName.equals(name);
721: }
722: return found;
723: }
724: }
|