View Javadoc
1   /**
2    * Copyright 2014 Internet2
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  /*
17    Copyright (C) 2004-2007 University Corporation for Advanced Internet Development, Inc.
18    Copyright (C) 2004-2007 The University Of Chicago
19  
20    Licensed under the Apache License, Version 2.0 (the "License");
21    you may not use this file except in compliance with the License.
22    You may obtain a copy of the License at
23  
24      http://www.apache.org/licenses/LICENSE-2.0
25  
26    Unless required by applicable law or agreed to in writing, software
27    distributed under the License is distributed on an "AS IS" BASIS,
28    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29    See the License for the specific language governing permissions and
30    limitations under the License.
31  */
32  
33  package edu.internet2.middleware.grouper;
34  import java.sql.Timestamp;
35  import java.util.ArrayList;
36  import java.util.Collection;
37  import java.util.Date;
38  import java.util.HashSet;
39  import java.util.Iterator;
40  import java.util.LinkedHashSet;
41  import java.util.Set;
42  
43  import org.apache.commons.lang.StringUtils;
44  import org.apache.commons.logging.Log;
45  
46  import edu.internet2.middleware.grouper.Stem.Scope;
47  import edu.internet2.middleware.grouper.attr.AttributeDef;
48  import edu.internet2.middleware.grouper.attr.finder.AttributeDefFinder;
49  import edu.internet2.middleware.grouper.exception.AttributeDefNotFoundException;
50  import edu.internet2.middleware.grouper.exception.GroupNotFoundException;
51  import edu.internet2.middleware.grouper.exception.GrouperException;
52  import edu.internet2.middleware.grouper.exception.InsufficientPrivilegeException;
53  import edu.internet2.middleware.grouper.exception.MemberNotFoundException;
54  import edu.internet2.middleware.grouper.exception.MembershipNotFoundException;
55  import edu.internet2.middleware.grouper.exception.QueryException;
56  import edu.internet2.middleware.grouper.exception.SchemaException;
57  import edu.internet2.middleware.grouper.exception.StemNotFoundException;
58  import edu.internet2.middleware.grouper.internal.dao.MembershipDAO;
59  import edu.internet2.middleware.grouper.internal.dao.QueryOptions;
60  import edu.internet2.middleware.grouper.internal.dao.QueryPaging;
61  import edu.internet2.middleware.grouper.membership.MembershipResult;
62  import edu.internet2.middleware.grouper.membership.MembershipSubjectContainer;
63  import edu.internet2.middleware.grouper.membership.MembershipType;
64  import edu.internet2.middleware.grouper.misc.CompositeType;
65  import edu.internet2.middleware.grouper.misc.E;
66  import edu.internet2.middleware.grouper.misc.GrouperDAOFactory;
67  import edu.internet2.middleware.grouper.privs.AccessPrivilege;
68  import edu.internet2.middleware.grouper.privs.AttributeDefPrivilege;
69  import edu.internet2.middleware.grouper.privs.NamingPrivilege;
70  import edu.internet2.middleware.grouper.privs.Privilege;
71  import edu.internet2.middleware.grouper.privs.PrivilegeHelper;
72  import edu.internet2.middleware.grouper.service.ServiceRole;
73  import edu.internet2.middleware.grouper.subj.LazySubject;
74  import edu.internet2.middleware.grouper.util.GrouperUtil;
75  import edu.internet2.middleware.grouperClient.collections.MultiKey;
76  import edu.internet2.middleware.grouperClient.jdbc.GcDbAccess;
77  import edu.internet2.middleware.grouperClient.util.ExpirableCache;
78  import edu.internet2.middleware.subject.Source;
79  import edu.internet2.middleware.subject.Subject;
80  import edu.internet2.middleware.subject.SubjectNotFoundException;
81  import edu.internet2.middleware.subject.provider.SourceManager;
82  
83  /**
84   * <p>Use this class to find memberships within the Groups registry</p>
85   * <p> 
86   * A membership is the object which represents a join of member
87   * and group.  Has metadata like type and creator,
88   * and, if an effective membership, the parent membership
89   * </p>
90   * <p>Sample call
91   * 
92   * <blockquote>
93   * <pre>
94   * Membership membership1 = new MembershipFinder().addGroup(group1).addSubject(subject).assignEnabled(true).findMembership(true);
95   * </pre>
96   * </blockquote>
97   * 
98   * </p>
99   * 
100  * <p> Sample call to find multiple memberships
101  * <blockquote>
102  * <pre>
103  * Set<Object[]> members = new MembershipFinder().addMembershipId(membership1.getUuid()).addMembershipId(membership2.getUuid()).findMembershipsMembers();
104  * </pre>
105  * </blockquote>
106  * </p>
107  * 
108  * <p> Sample call to find immediate memberships of a user
109  * <blockquote>
110  * <pre>
111  * Set membershipsOwnersMembers = new MembershipFinder().addSubject(subject).addField(Group.getDefaultList()).assignMembershipType(MembershipType.IMMEDIATE).assignEnabled(true).findMembershipResult().getMembershipsOwnersMembers();
112  *
113  * for (Object membershipsOwnersMember : GrouperUtil.nonNull(membershipsOwnersMembers)) {
114  *   Group group = (Group)((Object[])membershipsOwnersMember)[1];
115  *   System.out.println(group.getName());
116  * }
117  * </pre>
118  * </blockquote>
119  * </p>
120  *     
121  */
122 public class MembershipFinder {
123 
124   /**
125    * take in the group uuid or name and the subject and cache if in group for 2 minutes
126    */
127   private static ExpirableCache<MultiKey, Boolean> groupUuidOrNameSubjectSourceIdSubjectIdToInGroup = new ExpirableCache<>(2);
128   
129   /**
130    * see if subject is in group, do not check READ security, and cache for two minutes
131    * @param groupUuidOrName
132    * @param subject
133    * @return true if in group and false if not
134    */
135   public static boolean hasMemberCacheNoCheckSecurity(String groupUuidOrName, Subject subject) {
136     
137     MultiKey groupUuidOrNameSubjectSourceIdSubjectId = new MultiKey(groupUuidOrName, subject.getSourceId(), subject.getId());
138     
139     Boolean hasMember = groupUuidOrNameSubjectSourceIdSubjectIdToInGroup.get(groupUuidOrNameSubjectSourceIdSubjectId);
140     if (hasMember == null) {
141       
142       String sql = "select count(1) from grouper_memberships_lw_v gmlv "
143           + " where group_" + (groupUuidOrName.contains(":") ? "name" : "id") + " = ? and subject_source = ? and subject_id = ? and list_name = 'members'";
144 
145       int rows = new GcDbAccess().sql(sql).addBindVar(groupUuidOrName).addBindVar(subject.getSourceId()).addBindVar(subject.getId()).select(int.class);
146       hasMember = rows > 0;
147       groupUuidOrNameSubjectSourceIdSubjectIdToInGroup.put(groupUuidOrNameSubjectSourceIdSubjectId, hasMember);
148     }
149     return hasMember;
150     
151   }
152   
153   /**
154    * if the subject has a membership in the group
155    */
156   private Subject subjectHasMembershipForGroup;
157   
158   /**
159    * if the subject has a membership in the group
160    */
161   public MembershipFinder assignSubjectHasMembershipForGroup(Subject theSubjectHasMembershipForGroup) {
162     this.subjectHasMembershipForGroup = theSubjectHasMembershipForGroup;
163     return this;
164   }
165   
166   /**
167    * return memberships where the member has this field, note, it will return all the memberships for those members
168    */
169   private boolean hasMembershipTypeForMember;
170 
171   /**
172    * return memberships where the member has this field, note, it will return all the memberships for those members
173    * @param theHasMembershipType
174    * @return this for chaining
175    */
176   public MembershipFinder assignHasMembershipTypeForMember(boolean theHasMembershipType) {
177     this.hasMembershipTypeForMember = theHasMembershipType;
178     return this;
179   }
180 
181   /** 
182    * return memberships where the member has this field, note, it will return all the memberships for those members 
183    */
184   private boolean hasFieldForMember;
185 
186   /** 
187    * return memberships where the group has this field, note, it will return all the memberships for those groups 
188    */
189   private boolean hasFieldForGroup;
190 
191   /**
192    * return memberships where the group has this field, note, it will return all the memberships for those members 
193    * @return this for chaining
194    */
195   public MembershipFinder assignHasFieldForGroup(boolean theHasFieldForGroup) {
196     this.hasFieldForGroup = theHasFieldForGroup;
197     return this;
198   }
199   
200   /**
201    * return memberships where the member has this field, note, it will return all the memberships for those members 
202    * @param theHasField
203    * @return this for chaining
204    */
205   public MembershipFinder assignHasFieldForMember(boolean theHasField) {
206     this.hasFieldForMember = theHasField;
207     return this;
208   }
209   
210   /** if searching point in time data, the start of the range of the point in time query. */
211   private Timestamp pointInTimeFrom;
212   
213   /** if searching point in time data, the end of the range of the point in time query. */
214   private Timestamp pointInTimeTo;
215   
216   /**
217    * if searching point in time data, the start of the range of the point in time query.
218    * @param pointInTimeFrom1
219    * @return this for chaining
220    */
221   public MembershipFinder assignPointInTimeFrom(Timestamp pointInTimeFrom1) {
222     this.pointInTimeFrom = pointInTimeFrom1;
223     return this;
224   }
225   
226   /**
227    * if searching point in time data, the end of the range of the point in time query.
228    * @param pointInTimeTo1
229    * @return this for chaining
230    */
231   public MembershipFinder assignPointInTimeTo(Timestamp pointInTimeTo1) {
232     this.pointInTimeTo = pointInTimeTo1;
233     return this;
234   }
235 
236   /** membership ids to search for */
237   private Collection<String> membershipIds;
238 
239   /** membership type to look for */
240   private MembershipType membershipType;
241 
242   /** fields to look for */
243   private Collection<Field> fields = new HashSet<Field>();
244 
245   /**
246    * for group membership queries, pass in the privileges the user has
247    */
248   private Collection<Privilege> privilegesTheUserHas = new HashSet<Privilege>();
249 
250   
251   
252   /** sql like string to limit the results of the owner */
253   private String scope;
254   
255   /**
256    * sql like string to limit the results of the owner
257    * @param scope1
258    * @return this for chaining
259    */
260   public MembershipFinder assignScope(String scope1) {
261     this.scope = scope1;
262     return this;
263   }
264   
265   /**
266    * assign a field to filter by
267    * @param theField
268    * @return this for chaining
269    */
270   public MembershipFinder assignField(Field theField) {
271     this.fields.clear();
272     if (theField != null) {
273     this.fields.add(theField);
274     }
275     return this;
276   }
277   
278   /**
279    * assign a field to filter by, or a privilege name
280    * @param theField
281    * @return this for chaining
282    */
283   public MembershipFinder assignFieldName(String theFieldOrPrivilegeName) {
284     Field theField = FieldFinder.find(theFieldOrPrivilegeName, true);
285     this.assignField(theField);
286     return this;
287   }
288   
289   /** sources to look in */
290   private Set<Source> sources;
291 
292   /** stem to look in */
293   private Stem stem;
294 
295   /** stem scope to look in */
296   private Scope stemScope;
297   
298   /**
299    * field type to look for, mutually exclusive with fieldId
300    */
301   private FieldType fieldType;
302 
303   /**
304    * assign a field type, mutually exclusive with fieldId
305    * @param theFieldType
306    * @return this for chaining
307    */
308   public MembershipFinder assignFieldType(FieldType theFieldType) {
309     this.fieldType = theFieldType;
310     return this;
311   }
312   
313   /** if we should check security */
314   private boolean checkSecurity = true;
315 
316   /** if filtering by service role, this is the service id (id of the attributeDefName for service */
317   private String serviceId = null; 
318 
319   /**
320    * if filtering by serviceRole, this is the role, e.g. user or admin
321    */
322   private ServiceRole serviceRole = null;
323 
324   /**
325    * if filtering by service role, this is the service id (id of the attributeDefName for service
326    * @param serviceId1
327    * @return this for chaining
328    */
329   public MembershipFinder assignServiceId(String serviceId1) {
330     this.serviceId = serviceId1;
331     return this;
332   }
333   
334   /**
335    * if filtering by service role, this is the service id (id of the attributeDefName for service
336    * @param serviceRole1
337    * @return this for chaining
338    */
339   public MembershipFinder assignServiceRole(ServiceRole serviceRole1) {
340     this.serviceRole = serviceRole1;
341     return this;
342   }
343   
344   /**
345    * assign a stem scope to look in
346    * @param theStemScope
347    * @return this for chaining
348    */
349   public MembershipFinder assignStemScope(Scope theStemScope) {
350     this.stemScope = theStemScope;
351     return this;
352   }
353   
354   /**
355    * assign a stem to search in
356    * @param theStem
357    * @return this for chaining
358    */
359   public MembershipFinder assignStem(Stem theStem) {
360     this.stem = theStem;
361     return this;
362   }
363   
364   /**
365    * assign if this should check security or run as grouper system
366    * @param shouldCheckSecurity
367    * @return this for chaining
368    */
369   public MembershipFinder assignCheckSecurity(boolean shouldCheckSecurity) {
370     this.checkSecurity = shouldCheckSecurity;
371     return this;
372   }
373   
374   /**
375    * 
376    */
377   private Collection<String> memberIds = null;
378   
379   /**
380    * add a member id to the search criteria
381    * @param memberId
382    * @return this for chaining
383    */
384   public MembershipFinder addMemberId(String memberId) {
385     if (this.memberIds == null) {
386       this.memberIds = new ArrayList<String>();
387     }
388     //no need to look for dupes
389     if (!this.memberIds.contains(memberId)) {
390       this.memberIds.add(memberId);
391     }
392     return this;
393   }
394 
395   /**
396    * add a membership id to the search criteria
397    * @param membershipId
398    * @return this for chaining
399    */
400   public MembershipFinder addMembershipId(String membershipId) {
401     if (this.membershipIds == null) {
402       this.membershipIds = new ArrayList<String>();
403     }
404     //no need to look for dupes
405     if (!this.membershipIds.contains(membershipId)) {
406       this.membershipIds.add(membershipId);
407     }
408     return this;
409   }
410 
411   /**
412    * add subjects
413    * @param subjects
414    * @return this for chaining
415    */
416   public MembershipFinder addSubjects(Collection<Subject> subjects) {
417     
418     Set<Member> members = MemberFinder.findBySubjects(subjects, false);
419     
420     for (Member member : GrouperUtil.nonNull(members)) {
421       this.addMemberId(member.getUuid());
422     }
423     return this;
424   }
425   
426   /**
427    * assign a collection of member ids to look for
428    * @param theMemberIds
429    * @return this for chaining
430    */
431   public MembershipFinder assignMemberIds(Collection<String> theMemberIds) {
432     this.memberIds = theMemberIds;
433     return this;
434   }
435   
436   /**
437    * assign a collection of group ids to look for
438    * @param theGroupIds
439    * @return this for chaining
440    */
441   public MembershipFinder assignGroupIds(Collection<String> theGroupIds) {
442     this.groupIds = theGroupIds;
443     return this;
444   }
445   
446   /**
447    * assign a collection of fields to look for
448    * @param theFields
449    * @return this for chaining
450    */
451   public MembershipFinder assignFields(Collection<Field> theFields) {
452     this.fields = theFields;
453     return this;
454   }
455   
456   /**
457    * assign a collection of privileges (fields) to look for
458    * @param thePrivileges
459    * @return this for chaining
460    */
461   public MembershipFinder assignPrivileges(Collection<Privilege> thePrivileges) {
462     this.fields = Privilege.convertPrivilegesToFields(thePrivileges);
463     return this;
464   }
465   
466   /**
467    * assign a collection of fields to look for
468    * @param theFieldNames
469    * @return this for chaining
470    */
471   public MembershipFinder assignFieldsByName(Collection<String> theFieldNames) {
472     
473     Set<Field> theFields = new HashSet<Field>();
474 
475     for (String fieldName : GrouperUtil.nonNull(theFieldNames)) {
476       Field field = FieldFinder.find(fieldName, true);
477       theFields.add(field);
478     }
479     
480     this.fields = theFields;
481     
482     return this;
483   }
484   
485   /**
486    * assign a collection of stem ids to look for
487    * @param theStemIds
488    * @return this for chaining
489    */
490   public MembershipFinder assignStemIds(Collection<String> theStemIds) {
491     this.stemIds = theStemIds;
492     return this;
493   }
494 
495   /**
496    * assign a collection of attributeDef ids to look for
497    * @param theAttributeDefIds
498    * @return this for chaining
499    */
500   public MembershipFinder assignAttributeDefIds(Collection<String> theAttributeDefIds) {
501     this.attributeDefIds = theAttributeDefIds;
502     return this;
503   }
504   
505 
506   /**
507    * assign a membership type
508    * @param theMembershipType
509    * @return this for chaining
510    */
511   public MembershipFinder assignMembershipType(MembershipType theMembershipType) {
512     this.membershipType = theMembershipType;
513     return this;
514   }
515   
516   /**
517    * assign a collection of membership ids to look for
518    * @param theMembershipIds
519    * @return this for chaining
520    */
521   public MembershipFinder assignMembershipIds(Collection<String> theMembershipIds) {
522     this.membershipIds = theMembershipIds;
523     return this;
524   }
525   
526   /**
527    * add a subject to look for.
528    * @param subject
529    * @return this for chaining
530    */
531   public MembershipFinder addSubject(Subject subject) {
532     
533     //note, since we are chaining, we need to add if not found, since if we dont, it will find for
534     //all subjects if no more are added
535     Member member = MemberFinder.findBySubject(GrouperSession.staticGrouperSession(), subject, true);
536     return this.addMemberId(member.getUuid());
537   }
538   
539   /**
540    * 
541    */
542   private Collection<String> groupIds = null;
543   
544   /**
545    * add a role id to the search criteria
546    * @param groupId
547    * @return this for chaining
548    */
549   public MembershipFinder addGroupId(String groupId) {
550     if (!StringUtils.isBlank(groupId)) {
551       if (this.groupIds == null) {
552         this.groupIds = new ArrayList<String>();
553       }
554       //no need to look for dupes
555       if (!this.groupIds.contains(groupId)) {
556         this.groupIds.add(groupId);
557       }
558     }
559     return this;
560   }
561 
562   /**
563    * assign a collection of role ids to look for
564    * @param theRoleIds
565    * @return this for chaining
566    */
567   public MembershipFinder assignRoleIds(Collection<String> theRoleIds) {
568     this.groupIds = theRoleIds;
569     return this;
570   }
571   
572   /**
573    * assign a collection of sources to look for
574    * @param theSources
575    * @return this for chaining
576    */
577   public MembershipFinder assignSources(Set<Source> theSources) {
578     this.sources = theSources;
579     return this;
580   }
581   
582   /**
583    * add a role to look for.
584    * @param group
585    * @return this for chaining
586    */
587   public MembershipFinder addGroup(Group group) {
588     
589     return this.addGroupId(group.getId());
590   }
591   
592   /**
593    * add a role to look for by name.
594    * @param name
595    * @return this for chaining
596    */
597   public MembershipFinder addGroup(String name) {
598     
599     Group group = GroupFinder.findByName(GrouperSession.staticGrouperSession(), name, true);
600     
601     return this.addGroupId(group.getId());
602   }
603   
604   /**
605    * add a field to filter by
606    * @param name
607    * @return this for chaining
608    */
609   public MembershipFinder addField(String name) {
610     Field field = FieldFinder.find(name, false);
611     this.addField(field);
612     return this;
613   }
614   
615   /**
616    * add a field to filter by
617    * @param field
618    * @return this for chaining
619    */
620   public MembershipFinder addField(Field field) {
621     this.fields.add(field);
622     return this;
623   }
624 
625   /**
626    * add a privilege the user has for group query
627    * @param name
628    * @return this for chaining
629    */
630   public MembershipFinder addPrivilegeTheUserHas(String name) {
631     Privilege privilege = Privilege.getInstance(name);
632     this.addPrivilegeTheUserHas(privilege);
633     return this;
634   }
635   
636   /**
637    * add a privilege the user has for group query
638    * @param field
639    * @return this for chaining
640    */
641   public MembershipFinder addPrivilegeTheUserHas(Privilege field) {
642     this.privilegesTheUserHas.add(field);
643     return this;
644   }
645 
646   
647   /** if we should look for all, or enabled only.  default is all */
648   private Boolean enabled;
649   
650   /** if we should filter based on enable date being set */
651   private Boolean hasEnabledDate;
652   
653   /** if we should filter based on disabled date being set */
654   private Boolean hasDisabledDate;
655   
656   /** if we are are doing a custom composite, this is the composite type (intersection or complement) */
657   private CompositeType customCompositeType;
658   
659   /** if we are are doing a custom composite, this is the group */
660   private Group customCompositeGroup;
661   
662   /**
663    * 
664    */
665   private Collection<String> stemIds = null;
666 
667   /**
668    * 
669    */
670   private Collection<String> attributeDefIds = null;
671   
672   /**
673    * if we are are doing a custom composite, this is the composite type (intersection or complement)
674    * @param theCustomCompositeType
675    * @return this for chaining
676    */
677   public MembershipFinder assignCustomCompositeType(CompositeType theCustomCompositeType) {
678     this.customCompositeType = theCustomCompositeType;
679     return this;
680   }
681   
682   /**
683    * if we are are doing a custom composite, this is the group
684    * @param theCustomCompositeGroup
685    * @return this for chaining
686    */
687   public MembershipFinder assignCustomCompositeGroup(Group theCustomCompositeGroup) {
688     this.customCompositeGroup = theCustomCompositeGroup;
689     return this;
690   }
691   
692   /**
693    * true means enabled only, false, means disabled only, and null means all
694    * @param theEnabled
695    * @return this for chaining
696    */
697   public MembershipFinder assignEnabled(Boolean theEnabled) {
698     this.enabled = theEnabled;
699     return this;
700   }
701   
702   /**
703    * true means memberships with enabled dates
704    * false means memberships without enabled dates
705    * null means don't filter based on this (default)
706    * @param theHasEnabledDate
707    * @return this for chaining
708    */
709   public MembershipFinder assignHasEnabledDate(Boolean theHasEnabledDate) {
710     this.hasEnabledDate = theHasEnabledDate;
711     return this;
712   }
713   
714   /**
715    * true means memberships with disabled dates
716    * false means memberships without disabled dates
717    * null means don't filter based on this (default)
718    * @param theHasDisabledDate
719    * @return this for chaining
720    */
721   public MembershipFinder assignHasDisabledDate(Boolean theHasDisabledDate) {
722     this.hasDisabledDate = theHasDisabledDate;
723     return this;
724   }
725   
726   /**
727    * based on what you are querying for, see if has membership.
728    * Note, you should be looking for one subject, 
729    * one group, one field, etc
730    * If you are looking for multiple, it will see if anyone has that membership or any group
731    * @return true if has membership, false if not
732    */
733   public boolean hasMembership() {
734     
735     return GrouperUtil.length(findMembershipsGroupsMembers()) > 0;
736   }
737   
738   /**
739    * membership result gives helper methods in processing the results
740    * @return the membership result
741    */
742   public MembershipResult findMembershipResult() {
743     
744     Set<Object[]> membershipsOwnersMembers = this.findMembershipsMembers();
745     Field field = this.field(true);
746     String theFieldId = field == null ? null : field.getUuid();
747     
748     Collection<Field> theFields = this.fields;
749     
750     if (this.hasFieldForGroup || this.hasFieldForStem || this.hasFieldForAttributeDef || this.hasFieldForMember) {
751       theFields = null;
752     }
753     
754     boolean theIncludeInheritedPrivileges = this.includeInheritedPrivileges;
755     
756     if (this.hasFieldForGroup || this.hasFieldForStem || this.hasFieldForAttributeDef || this.hasFieldForMember) {
757       theIncludeInheritedPrivileges = false;
758     }
759     
760     return new MembershipResult(membershipsOwnersMembers, theFieldId, theFields, 
761         theIncludeInheritedPrivileges);
762   }
763   
764   /**
765    * if inherited effective privileges should be included.  i.e. if you query for UPDATE, then also query for ADMIN
766    */
767   private boolean includeInheritedPrivileges = false;
768   
769   /**
770    * if inherited effective privileges should be included.  i.e. if you query for UPDATE, then also query for ADMIN
771    * @param theIncludeInheritedPrivileges
772    * @return this for chaining
773    */
774   public MembershipFinder assignIncludeInheritedPrivileges(boolean theIncludeInheritedPrivileges) {
775     this.includeInheritedPrivileges = theIncludeInheritedPrivileges;
776     return this;
777   }
778   
779   /**
780    * assuming one field
781    * @param firstFieldIfMultiple true if should get first field if multiple
782    * @return the field or null
783    */
784   private Field field(boolean firstFieldIfMultiple) {
785     if (!firstFieldIfMultiple) {
786       this.assertOneOrNoFields();
787     }
788     if (GrouperUtil.length(this.fields) == 0) {
789       return null;
790     }
791     if (GrouperUtil.length(this.fields) == 1) {
792       return this.fields.iterator().next();
793     }
794     //at this point there are multiple... make sure same type?  or dont worry?
795     FieldType fieldType = null;
796     for (Field field : this.fields) {
797       if (fieldType == null) {
798         fieldType = field.getType();
799       } else {
800         if (fieldType != field.getType()) {
801           throw new RuntimeException("Expecting field type of: " + fieldType + ", but received: " + field.getType());
802         }
803       }
804     }
805     return this.fields.iterator().next();
806   }
807   
808   /**
809    * make sure there is only one or no fields here
810    */
811   private void assertOneOrNoFields() {
812     if (GrouperUtil.length(this.fields) <= 1) {
813       return;
814     }
815     throw new RuntimeException("Expecting 0 or 1 fields but got: " + GrouperUtil.length(this.fields));
816   }
817   
818   
819   /**
820    * if true then find all fields in all membership and priv owners
821    */
822   private boolean findAllFields = false;
823   /**
824    * if true then find all fields in all membership and priv owners
825    * @param theFindAllFields
826    * @return this for chaining
827    */
828   public MembershipFinder assignFindAllFields(boolean theFindAllFields) {
829     this.findAllFields = theFindAllFields;
830     return this;
831   }
832   
833   
834   /**
835    * find a set of object arrays which have a membership, group|stem|attributeDef, and member inside
836    * @return the set of arrays never null
837    */
838   public Set<Object[]> findMembershipsMembers() {
839     
840     if (pointInTimeFrom != null || pointInTimeTo != null) {
841       throw new RuntimeException("Use findPITMembershipsMembers() for point in time queries");
842     }
843     
844     if (this.findAllFields) {
845       
846       if (GrouperUtil.length(this.fields) > 0) {
847         throw new RuntimeException("Cannot findAllFields and pass in a field");
848       }
849       
850       Set<Object[]> totalResults = new LinkedHashSet<Object[]>();
851       this.findAllFields = false;
852       
853       // memberships
854       this.fields =  GrouperUtil.toSet(Group.getDefaultList());
855       totalResults.addAll(GrouperUtil.nonNull(this.findMembershipsMembers()));
856       
857       // group privs
858       this.fields =  Privilege.convertPrivilegesToFields(AccessPrivilege.ALL_PRIVILEGES);
859       totalResults.addAll(GrouperUtil.nonNull(this.findMembershipsMembers()));
860       
861       // stem privs
862       this.fields =  Privilege.convertPrivilegesToFields(NamingPrivilege.ALL_PRIVILEGES);
863       totalResults.addAll(GrouperUtil.nonNull(this.findMembershipsMembers()));
864       // attr def privs
865       this.fields =  Privilege.convertPrivilegesToFields(AttributeDefPrivilege.ALL_PRIVILEGES);
866       totalResults.addAll(GrouperUtil.nonNull(this.findMembershipsMembers()));
867       
868       this.findAllFields = true;
869       this.fields = null;
870       
871       return totalResults;
872       
873     } 
874     
875     Field field = this.field(true);
876     if ((this.fieldType != null && this.fieldType == FieldType.NAMING )
877         || (field != null && field.isStemListField())
878         || GrouperUtil.length(this.stemIds) > 0) {
879       return this.findMembershipsStemsMembers();
880     } else if ((this.fieldType != null && this.fieldType == FieldType.ATTRIBUTE_DEF )
881         || (field != null && field.isAttributeDefListField())
882         || GrouperUtil.length(this.attributeDefIds) > 0) {
883       Set<Object[]> result = this.findMembershipsAttributeDefsMembers();
884       return result;
885     } else if ((field == null && this.fieldType == null) 
886         || this.fieldType == FieldType.ACCESS || this.fieldType == FieldType.LIST
887         || (field != null && field.isGroupListField())
888         || GrouperUtil.length(this.groupIds) > 0) {
889       return this.findMembershipsGroupsMembers();
890     } else {
891       throw new RuntimeException("Not expecting field / fieldType: " + field + ", " + this.fieldType);
892     }
893   }
894   
895   /**
896    * find a set of object arrays which have a membership, group, and member inside
897    * @return the set of arrays never null
898    */
899   private Set<Object[]> findMembershipsGroupsMembers() {
900 
901     //validate that we are looking at groups
902     Field field = this.field(true);
903     if (field != null && !field.isGroupAccessField() && !field.isGroupListField()) {
904       throw new RuntimeException("Not expecting field: " + field +
905           ", expecting a group field since other part of the query involve group memberships");
906     }
907 
908     if (this.fieldType != null && this.fieldType != FieldType.ACCESS && this.fieldType != FieldType.LIST) {
909       throw new RuntimeException("Not expecting fieldType: " + this.fieldType +
910           ", expecting a group field type since other part of the query involve group memberships");
911     }
912 
913     if (GrouperUtil.length(this.stemIds) > 0) {
914       throw new RuntimeException("Not expecting stem lookups, since other parts of the query "
915           + " involve group memberships");
916       
917     }
918     
919     if (GrouperUtil.length(this.attributeDefIds) > 0) {
920       throw new RuntimeException("Not expecting attribute definition lookups, since other parts of the query "
921           + " involve group memberships");
922     }
923 
924     Collection<Field> inheritedFields = Field.calculateInheritedPrivileges(this.fields, this.includeInheritedPrivileges);
925     
926     Member memberHasMembershipForGroup = null;
927     
928     if (this.subjectHasMembershipForGroup != null) {
929       memberHasMembershipForGroup = MemberFinder.findBySubject(GrouperSession.staticGrouperSession(), 
930           this.subjectHasMembershipForGroup, false);
931       if (memberHasMembershipForGroup == null) {
932         return new HashSet<Object[]>();
933       }
934     }
935     
936     return GrouperDAOFactory.getFactory().getMembership().findAllByGroupOwnerOptions(this.groupIds, this.memberIds,
937         this.membershipIds, this.membershipType, inheritedFields, this.privilegesTheUserHas, this.sources, this.scope, this.stem, this.stemScope, 
938         this.enabled, this.checkSecurity, this.fieldType, this.serviceId, this.serviceRole,
939         this.queryOptionsForMember, this.scopeForMember, this.splitScopeForMember, 
940         this.hasFieldForMember, this.hasMembershipTypeForMember, this.queryOptionsForGroup, 
941         this.scopeForGroup, this.splitScopeForGroup, this.hasFieldForGroup,
942         this.hasMembershipTypeForGroup, memberHasMembershipForGroup, this.hasEnabledDate, this.hasDisabledDate, this.customCompositeType, this.customCompositeGroup, this.queryOptionsForMembership);  
943 
944 
945   }
946   
947   /**
948    * find a set of object arrays which have a PITMembershipView, PITGroup|PITStem|PITAttributeDef, PITMember, and Member inside
949    * note that for now this only supports stem, stemScope, groupIds, memberIds, sources, checkSecurity, queryOptionsForMember, scopeForMember, hasFieldForMember, pointInTimeFrom, and pointInTimeTo
950    * @return the set of arrays never null
951    */
952   public Set<Object[]> findPITMembershipsMembers() {
953     return this.findPITMembershipsGroupsMembers();
954   }
955   
956   
957   /**
958    * find a set of object arrays which have a PITMembershipView, PITGroup, PITMember and Member inside
959    * note that for now this only supports stem, stemScope, groupIds, memberIds, sources, checkSecurity, queryOptionsForMember, scopeForMember, hasFieldForMember, pointInTimeFrom, and pointInTimeTo
960    * @return the set of arrays never null
961    */
962   private Set<Object[]> findPITMembershipsGroupsMembers() {
963 
964     //validate that we are looking at groups
965     Field field = this.field(true);
966     if (field != null && !field.isGroupAccessField() && !field.isGroupListField()) {
967       throw new RuntimeException("Not expecting field: " + field +
968           ", expecting a group field since other part of the query involve group memberships");
969     }
970 
971     if (this.fieldType != null && this.fieldType != FieldType.ACCESS && this.fieldType != FieldType.LIST) {
972       throw new RuntimeException("Not expecting fieldType: " + this.fieldType +
973           ", expecting a group field type since other part of the query involve group memberships");
974     }
975 
976     if (GrouperUtil.length(this.stemIds) > 0) {
977       throw new RuntimeException("Not expecting stem lookups, since other parts of the query "
978           + " involve group memberships");
979       
980     }
981     
982     if (GrouperUtil.length(this.attributeDefIds) > 0) {
983       throw new RuntimeException("Not expecting attribute definition lookups, since other parts of the query "
984           + " involve group memberships");
985     }
986     
987     return GrouperDAOFactory.getFactory().getPITMembershipView().findAllByGroupOwnerOptions(this.groupIds, this.memberIds, this.fields, this.sources, this.stem, this.stemScope, this.checkSecurity, this.fieldType, 
988         this.queryOptionsForMember, this.scopeForMember, this.splitScopeForMember, this.hasFieldForMember, this.pointInTimeFrom, this.pointInTimeTo);
989   }
990 
991   /**
992    * find a set of object arrays which have a membership, stem, and member inside
993    * @return the set of arrays never null
994    */
995   private Set<Object[]> findMembershipsStemsMembers() {
996 
997     Collection<Field> inheritedFields = Field.calculateInheritedPrivileges(this.fields, this.includeInheritedPrivileges);
998     
999     //validate that we are looking at stems
1000     Field field = this.field(true);
1001     if (field != null && !field.isStemListField()) {
1002       throw new RuntimeException("Not expecting field: " + field +
1003           ", expecting a stem field since other part of the query involve stem memberships");
1004     }
1005 
1006     if (this.fieldType != null && this.fieldType != FieldType.NAMING) {
1007       throw new RuntimeException("Not expecting fieldType: " + this.fieldType +
1008           ", expecting a stem field type since other part of the query involve stem memberships");
1009     }
1010 
1011     if (GrouperUtil.length(this.groupIds) > 0) {
1012       throw new RuntimeException("Not expecting group lookups, since other parts of the query "
1013           + " involve stem memberships");
1014       
1015     }
1016     
1017     if (GrouperUtil.length(this.attributeDefIds) > 0) {
1018       throw new RuntimeException("Not expecting attribute definition lookups, since other parts of the query "
1019           + " involve stem memberships");
1020     }
1021 
1022     return GrouperDAOFactory.getFactory().getMembership().findAllByStemOwnerOptions(this.stemIds, this.memberIds,
1023         this.membershipIds, this.membershipType, inheritedFields, this.sources, 
1024         this.scope, this.stem, this.stemScope, this.enabled, this.checkSecurity, 
1025         this.queryOptionsForMember, this.scopeForMember, this.splitScopeForMember, 
1026         this.hasFieldForMember, this.hasMembershipTypeForMember, this.queryOptionsForStem, 
1027         this.scopeForStem, this.splitScopeForStem, this.hasFieldForStem,
1028         this.hasMembershipTypeForStem, this.hasEnabledDate, this.hasDisabledDate,
1029         this.customCompositeType, this.customCompositeGroup);  
1030 
1031   }
1032 
1033   /**
1034    * find a membership
1035    * @param exceptionIfNotFound true if exception should be thrown if permission not found
1036    * @return the permission or null
1037    */
1038   public Membership findMembership(boolean exceptionIfNotFound) {
1039 
1040     Set<Object[]> memberships = findMembershipsMembers();
1041     
1042     //this should find one if it is there...
1043     Membership membership = null;
1044     
1045     if (GrouperUtil.length(memberships) > 1) {
1046       throw new RuntimeException("Why is there more than one membership found? " + this);
1047     }
1048     
1049     if (GrouperUtil.length(memberships) == 1) {
1050       membership = (Membership)memberships.iterator().next()[0];
1051     }
1052     
1053     if (membership == null && exceptionIfNotFound) {
1054       throw new RuntimeException("could not find membership: " 
1055           + this);
1056     }
1057     return membership;
1058     
1059   }
1060 
1061   /**
1062    * @see Object#toString()
1063    */
1064   @Override
1065   public String toString() {
1066     StringBuilder result = new StringBuilder();
1067     if (enabled != null) {
1068       result.append("enabled: ").append(this.enabled);
1069     }
1070     if (GrouperUtil.length(this.memberIds) > 0) {
1071       result.append("memberIds: ").append(GrouperUtil.toStringForLog(this.memberIds, 100));
1072     }
1073     if (GrouperUtil.length(this.fields) > 0) {
1074       result.append("fields: ").append(GrouperUtil.toStringForLog(this.fields, 100));
1075     }
1076     if (GrouperUtil.length(this.groupIds) > 0) {
1077       result.append("groupIds: ").append(GrouperUtil.toStringForLog(this.groupIds, 100));
1078     }
1079     if (GrouperUtil.length(this.membershipIds) > 0) {
1080       result.append("membershipIds: ").append(GrouperUtil.toStringForLog(this.membershipIds, 100));
1081     }
1082     if (GrouperUtil.length(this.membershipType) > 0) {
1083       result.append("membershipType: ").append(this.membershipType);
1084     }
1085     if (GrouperUtil.length(this.sources) > 0) {
1086       result.append("sources: ").append(GrouperUtil.toStringForLog(this.sources, 100));
1087     }
1088     if (GrouperUtil.length(this.stem) > 0) {
1089       result.append("stem: ").append(this.stem);
1090     }
1091     if (GrouperUtil.length(this.stemScope) > 0) {
1092       result.append("membershipType: ").append(this.membershipType);
1093     }
1094     return result.toString();
1095   }
1096 
1097   /**
1098    * add a stem to look for.
1099    * @param stem
1100    * @return this for chaining
1101    */
1102   public MembershipFinder addStem(Stem stem) {
1103     
1104     return this.addStemId(stem.getUuid());
1105   }
1106 
1107   /**
1108    * add a stem to look for by name.
1109    * @param name
1110    * @return this for chaining
1111    */
1112   public MembershipFinder addStem(String name) {
1113     
1114     Stem stem = StemFinder.findByName(GrouperSession.staticGrouperSession(), name, true);
1115     return this.addStemId(stem.getId());
1116   }
1117 
1118   /**
1119    * add a stem id to the search criteria
1120    * @param stemId
1121    * @return this for chaining
1122    */
1123   public MembershipFinder addStemId(String stemId) {
1124     if (!StringUtils.isBlank(stemId)) {
1125       if (this.stemIds == null) {
1126         this.stemIds = new ArrayList<String>();
1127       }
1128       //no need to look for dupes
1129       if (!this.stemIds.contains(stemId)) {
1130         this.stemIds.add(stemId);
1131       }
1132     }
1133     return this;
1134   }
1135 
1136   /**
1137    * add a sourceId to the search criteria
1138    * @param sourceId
1139    * @return this for chaining
1140    */
1141   public MembershipFinder addSourceId(String sourceId) {
1142     
1143     if (!StringUtils.isBlank(sourceId)) {
1144       Source source = SourceManager.getInstance().getSource(sourceId);
1145       addSource(source);
1146     }
1147     return this;
1148   }
1149 
1150   /**
1151    * add a source to the search criteria
1152    * @param source
1153    * @return this for chaining
1154    */
1155   public MembershipFinder addSource(Source source) {
1156     if (source != null) {
1157       if (this.sources == null) {
1158         this.sources = new HashSet<Source>();
1159       }
1160       //no need to look for dupes
1161       this.sources.add(source);
1162     }
1163     return this;
1164   }
1165 
1166   /**
1167    * find a set of object arrays which have a membership, attributeDef, and member inside
1168    * @return the set of arrays never null
1169    */
1170   private Set<Object[]> findMembershipsAttributeDefsMembers() {
1171   
1172     Collection<Field> inheritedFields = Field.calculateInheritedPrivileges(this.fields, this.includeInheritedPrivileges);
1173 
1174     //validate that we are looking at attribute definitions
1175     Field field = this.field(true);
1176     if (field != null && !field.isAttributeDefListField()) {
1177       throw new RuntimeException("Not expecting field: " + field +
1178           ", expecting an attribute definition field since other part of the query involve attribute definition memberships");
1179     }
1180 
1181     if (this.fieldType != null && this.fieldType != FieldType.ATTRIBUTE_DEF) {
1182       throw new RuntimeException("Not expecting fieldType: " + this.fieldType +
1183           ", expecting an attribute def field type since other part of the query involve attributeDef memberships");
1184     }
1185 
1186     if (GrouperUtil.length(this.groupIds) > 0) {
1187       throw new RuntimeException("Not expecting group lookups, since other parts of the query "
1188           + " involve attributeDef memberships");
1189       
1190     }
1191     
1192     if (GrouperUtil.length(this.stemIds) > 0) {
1193       throw new RuntimeException("Not expecting stem lookups, since other parts of the query "
1194           + " involve attributeDef memberships");
1195     }
1196 
1197     Set<Object[]> result = GrouperDAOFactory.getFactory().getMembership().findAllByAttributeDefOwnerOptions(this.attributeDefIds, this.memberIds,
1198         this.membershipIds, this.membershipType, inheritedFields, this.sources, this.scope, this.stem, this.stemScope, 
1199         this.enabled, this.checkSecurity, this.queryOptionsForMember, this.scopeForMember, this.splitScopeForMember, 
1200         this.hasFieldForMember, this.hasMembershipTypeForMember,
1201         this.queryOptionsForAttributeDef, this.scopeForAttributeDef, this.splitScopeForAttributeDef, this.hasFieldForAttributeDef, 
1202         this.hasMembershipTypeForAttributeDef, this.hasEnabledDate, this.hasDisabledDate, this.customCompositeType, this.customCompositeGroup);  
1203     return result;
1204   }
1205 
1206   /**
1207    * add a attributeDef to look for.
1208    * @param attributeDef
1209    * @return this for chaining
1210    */
1211   public MembershipFinder addAttributeDef(AttributeDef attributeDef) {
1212     
1213     return this.addAttributeDefId(attributeDef.getId());
1214   }
1215 
1216   /**
1217    * add a attributeDef to look for by name.
1218    * @param name
1219    * @return this for chaining
1220    */
1221   public MembershipFinder addAttributeDef(String name) {
1222     
1223     AttributeDef attributeDef = AttributeDefFinder.findByName(name, true);
1224     
1225     return this.addGroupId(attributeDef.getId());
1226   }
1227 
1228   /**
1229    * add a attributeDef id to the search criteria
1230    * @param attributeDefId
1231    * @return this for chaining
1232    */
1233   public MembershipFinder addAttributeDefId(String attributeDefId) {
1234     if (!StringUtils.isBlank(attributeDefId)) {
1235       if (this.attributeDefIds == null) {
1236         this.attributeDefIds = new ArrayList<String>();
1237       }
1238       //no need to look for dupes
1239       if (!this.attributeDefIds.contains(attributeDefId)) {
1240         this.attributeDefIds.add(attributeDefId);
1241       }
1242     }
1243     return this;
1244   }
1245 
1246   /**
1247    * @see edu.internet2.middleware.grouper.internal.dao.MembershipDAO#findAllByGroupOwnerOptions(java.util.Collection, java.util.Collection, java.util.Collection, edu.internet2.middleware.grouper.membership.MembershipType, edu.internet2.middleware.grouper.Field, Set, java.lang.String, edu.internet2.middleware.grouper.Stem, edu.internet2.middleware.grouper.Stem.Scope, java.lang.Boolean)
1248    * @param stemIds to limit memberships to (cant have more than 100 bind variables)
1249    * @param memberIds to limit memberships to (cant have more than 100 bind variables)
1250    * @param membershipIds to limit memberships to (cant have more than 100 bind variables)
1251    * @param membershipType Immediate, NonImmediate, etc
1252    * @param field if finding one field, list here, otherwise all list fields will be returned
1253    * @param sources if limiting memberships of members in certain sources, list here
1254    * @param scope sql like string which will have a % appended to it
1255    * @param stem if looking in a certain stem
1256    * @param stemScope if looking only in this stem, or all substems
1257    * @param enabled null for all, true for enabled only, false for disabled only
1258    * @param shouldCheckSecurity if we should check security, default to true
1259    * @return the set of arrays of Membership, Group, and Member
1260    */
1261   public static Set<Object[]> findStemMemberships(Collection<String> stemIds, Collection<String> memberIds,
1262       Collection<String> membershipIds, MembershipType membershipType,
1263       Field field,  
1264       Set<Source> sources, String scope, Stem stem, Scope stemScope, Boolean enabled, Boolean shouldCheckSecurity) {
1265     return GrouperDAOFactory.getFactory().getMembership().findAllByStemOwnerOptions(stemIds, memberIds,
1266         membershipIds, membershipType, field, sources, scope, stem, stemScope, enabled, shouldCheckSecurity);  
1267   }
1268 
1269   /**
1270    * @see edu.internet2.middleware.grouper.internal.dao.MembershipDAO#findAllByGroupOwnerOptions(java.util.Collection, java.util.Collection, java.util.Collection, edu.internet2.middleware.grouper.membership.MembershipType, edu.internet2.middleware.grouper.Field, Set, java.lang.String, edu.internet2.middleware.grouper.Stem, edu.internet2.middleware.grouper.Stem.Scope, java.lang.Boolean)
1271    * @param groupIds to limit memberships to (cant have more than 100 bind variables)
1272    * @param memberIds to limit memberships to (cant have more than 100 bind variables)
1273    * @param membershipIds to limit memberships to (cant have more than 100 bind variables)
1274    * @param membershipType Immediate, NonImmediate, etc
1275    * @param field if finding one field, list here, otherwise all list fields will be returned
1276    * @param sources if limiting memberships of members in certain sources, list here
1277    * @param scope sql like string which will have a % appended to it
1278    * @param stem if looking in a certain stem
1279    * @param stemScope if looking only in this stem, or all substems
1280    * @param enabled null for all, true for enabled only, false for disabled only
1281    * @param shouldCheckSecurity if we should check security, default to true
1282    * @return the set of arrays of Membership, Group, and Member
1283    */
1284   public static Set<Object[]> findMemberships(Collection<String> groupIds, Collection<String> memberIds,
1285       Collection<String> membershipIds, MembershipType membershipType,
1286       Field field,  
1287       Set<Source> sources, String scope, Stem stem, Scope stemScope, Boolean enabled, Boolean shouldCheckSecurity) {
1288     return findMemberships(groupIds, memberIds, membershipIds, membershipType, field, sources, scope, stem, stemScope, enabled, 
1289         shouldCheckSecurity, null);
1290   }
1291 
1292 
1293   /**
1294    * @see edu.internet2.middleware.grouper.internal.dao.MembershipDAO#findAllByGroupOwnerOptions(java.util.Collection, java.util.Collection, java.util.Collection, edu.internet2.middleware.grouper.membership.MembershipType, edu.internet2.middleware.grouper.Field, Set, java.lang.String, edu.internet2.middleware.grouper.Stem, edu.internet2.middleware.grouper.Stem.Scope, java.lang.Boolean)
1295    * @param groupIds to limit memberships to (cant have more than 100 bind variables)
1296    * @param memberIds to limit memberships to (cant have more than 100 bind variables)
1297    * @param membershipIds to limit memberships to (cant have more than 100 bind variables)
1298    * @param membershipType Immediate, NonImmediate, etc
1299    * @param field if finding one field, list here, otherwise all list fields will be returned
1300    * @param sources if limiting memberships of members in certain sources, list here
1301    * @param scope sql like string which will have a % appended to it
1302    * @param stem if looking in a certain stem
1303    * @param stemScope if looking only in this stem, or all substems
1304    * @param enabled null for all, true for enabled only, false for disabled only
1305    * @param shouldCheckSecurity if we should check security, default to true
1306    * @param fieldType is access or list
1307    * @return the set of arrays of Membership, Group, and Member
1308    */
1309   public static Set<Object[]> findMemberships(Collection<String> groupIds, Collection<String> memberIds,
1310       Collection<String> membershipIds, MembershipType membershipType,
1311       Field field,  
1312       Set<Source> sources, String scope, Stem stem, Scope stemScope, Boolean enabled, Boolean shouldCheckSecurity, FieldType fieldType) {
1313     return findMemberships(groupIds, memberIds, membershipIds, membershipType, field, sources, scope,
1314         stem, stemScope, enabled, shouldCheckSecurity, fieldType, null, null);
1315   }
1316 
1317   /**
1318    * Return the immediate membership if it exists.  
1319    * 
1320    * An immediate member is directly assigned to a stem.
1321    * A stem can have potentially unlimited effective 
1322    * memberships
1323    * 
1324    * <p/>
1325    * <pre class="eg">
1326    * </pre>
1327    * @param   s     Get membership within this session context.
1328    * @param   stem     Immediate membership has this group.
1329    * @param   subj  Immediate membership has this subject.
1330    * @param   f     Immediate membership has this list.
1331    * @param exceptionIfNotFound
1332    * @return  A {@link Membership} object
1333    * @throws  MembershipNotFoundException 
1334    * @throws  SchemaException
1335    */
1336   public static Membership findImmediateMembership(
1337     GrouperSession s, Stem stem, Subject subj, Field f, boolean exceptionIfNotFound
1338   ) throws  MembershipNotFoundException, SchemaException {
1339     //note, no need for GrouperSession inverse of control
1340     // @filtered  true
1341     // @session   true
1342     GrouperSession.validate(s);
1343     try {
1344       Member      m   = MemberFinder.findBySubject(s, subj, true);
1345       Membership  ms  = GrouperDAOFactory.getFactory().getMembership().findByStemOwnerAndMemberAndFieldAndType( 
1346           stem.getUuid(), m.getUuid(), f, MembershipType.IMMEDIATE.getTypeString(), true, true);
1347       PrivilegeHelper.dispatch( s, ms.getOwnerStem(), s.getSubject(), f.getReadPriv() );
1348       return ms;
1349     } catch (MembershipNotFoundException mnfe)         {
1350       if (exceptionIfNotFound) {
1351         throw mnfe;
1352       }
1353       return null;
1354     } catch (StemNotFoundException eGNF)         {
1355       //not sure why this should happen in a non-corrupt db
1356       if (exceptionIfNotFound) {
1357         throw new MembershipNotFoundException(eGNF.getMessage(), eGNF);
1358       }
1359       return null;
1360     } catch (InsufficientPrivilegeException eIP)  {
1361       if (exceptionIfNotFound) {
1362         throw new MembershipNotFoundException(eIP.getMessage(), eIP);
1363       }
1364       return null;
1365     }
1366   }
1367 
1368   /**
1369    * @see edu.internet2.middleware.grouper.internal.dao.MembershipDAO#findAllByGroupOwnerOptions(java.util.Collection, java.util.Collection, java.util.Collection, edu.internet2.middleware.grouper.membership.MembershipType, edu.internet2.middleware.grouper.Field, Set, java.lang.String, edu.internet2.middleware.grouper.Stem, edu.internet2.middleware.grouper.Stem.Scope, java.lang.Boolean)
1370    * @param groupIds to limit memberships to (cant have more than 100 bind variables)
1371    * @param memberIds to limit memberships to (cant have more than 100 bind variables)
1372    * @param membershipIds to limit memberships to (cant have more than 100 bind variables)
1373    * @param membershipType Immediate, NonImmediate, etc
1374    * @param field if finding one field, list here, otherwise all list fields will be returned
1375    * @param sources if limiting memberships of members in certain sources, list here
1376    * @param scope sql like string which will have a % appended to it
1377    * @param stem if looking in a certain stem
1378    * @param stemScope if looking only in this stem, or all substems
1379    * @param enabled null for all, true for enabled only, false for disabled only
1380    * @return the set of arrays of Membership, Group, and Member
1381    */
1382   public static Set<Object[]> findMemberships(Collection<String> groupIds, Collection<String> memberIds,
1383       Collection<String> membershipIds, MembershipType membershipType,
1384       Field field,  
1385       Set<Source> sources, String scope, Stem stem, Scope stemScope, Boolean enabled) {
1386     
1387     return findMemberships(groupIds, memberIds, membershipIds, membershipType, field, sources, scope, stem, stemScope, enabled, null, null);
1388     
1389   }
1390   
1391   
1392   /**
1393    * @see edu.internet2.middleware.grouper.internal.dao.MembershipDAO#findAllByGroupOwnerOptions(java.util.Collection, java.util.Collection, java.util.Collection, edu.internet2.middleware.grouper.membership.MembershipType, edu.internet2.middleware.grouper.Field, Set, java.lang.String, edu.internet2.middleware.grouper.Stem, edu.internet2.middleware.grouper.Stem.Scope, java.lang.Boolean)
1394    * @param attributeDefIds to limit memberships to (cant have more than 100 bind variables)
1395    * @param memberIds to limit memberships to (cant have more than 100 bind variables)
1396    * @param membershipIds to limit memberships to (cant have more than 100 bind variables)
1397    * @param membershipType Immediate, NonImmediate, etc
1398    * @param field if finding one field, list here, otherwise all list fields will be returned
1399    * @param sources if limiting memberships of members in certain sources, list here
1400    * @param scope sql like string which will have a % appended to it
1401    * @param stem if looking in a certain stem
1402    * @param stemScope if looking only in this stem, or all substems
1403    * @param enabled null for all, true for enabled only, false for disabled only
1404    * @param shouldCheckSecurity if we should check security, default to true
1405    * @return the set of arrays of Membership, Group, and Member
1406    */
1407   public static Set<Object[]> findAttributeDefMemberships(Collection<String> attributeDefIds, 
1408       Collection<String> memberIds,
1409       Collection<String> membershipIds, MembershipType membershipType,
1410       Field field,  
1411       Set<Source> sources, String scope, Stem stem, Scope stemScope, Boolean enabled, 
1412       Boolean shouldCheckSecurity) {
1413 
1414     return GrouperDAOFactory.getFactory().getMembership().findAllByAttributeDefOwnerOptions(attributeDefIds, memberIds,
1415         membershipIds, membershipType, field, sources, scope, stem, stemScope, enabled, shouldCheckSecurity);  
1416   
1417   }
1418   
1419   /**
1420    * @see edu.internet2.middleware.grouper.internal.dao.MembershipDAO#findAllByGroupOwnerOptions(java.util.Collection, java.util.Collection, java.util.Collection, edu.internet2.middleware.grouper.membership.MembershipType, edu.internet2.middleware.grouper.Field, Set, java.lang.String, edu.internet2.middleware.grouper.Stem, edu.internet2.middleware.grouper.Stem.Scope, java.lang.Boolean)
1421    * @param groupIds to limit memberships to (cant have more than 100 bind variables)
1422    * @param memberIds to limit memberships to (cant have more than 100 bind variables)
1423    * @param membershipIds to limit memberships to (cant have more than 100 bind variables)
1424    * @param membershipType Immediate, NonImmediate, etc
1425    * @param field if finding one field, list here, otherwise all list fields will be returned
1426    * @param sources if limiting memberships of members in certain sources, list here
1427    * @param scope sql like string which will have a % appended to it
1428    * @param stem if looking in a certain stem
1429    * @param stemScope if looking only in this stem, or all substems
1430    * @param enabled null for all, true for enabled only, false for disabled only
1431    * @param shouldCheckSecurity if we should check security, default to true
1432    * @param serviceId is the id of the service (attributeDefName) if filtering memberships of people in a service
1433    * @param serviceRole is the user/admin role of the user in the service
1434    * @return the set of arrays of Membership, Group, and Member
1435    */
1436   public static Set<Object[]> findMemberships(Collection<String> groupIds, Collection<String> memberIds,
1437       Collection<String> membershipIds, MembershipType membershipType,
1438       Field field,  
1439       Set<Source> sources, String scope, Stem stem, Scope stemScope, Boolean enabled, Boolean shouldCheckSecurity,
1440       FieldType fieldType, String serviceId, ServiceRole serviceRole) {    
1441     
1442     return GrouperDAOFactory.getFactory().getMembership().findAllByGroupOwnerOptions(groupIds, memberIds,
1443         membershipIds, membershipType, GrouperUtil.toSet(field), null, sources, scope, stem, stemScope, enabled, shouldCheckSecurity, 
1444         fieldType, serviceId, serviceRole, null, null, false, false, false, null, null, false, false, false, null);  
1445   }
1446   
1447   /**
1448    * Return the composite membership if it exists. 
1449    *
1450    * A composite group is composed of two groups and a set operator 
1451    * (stored in grouper_composites table)
1452    * (e.g. union, intersection, etc).  A composite group has no immediate members.
1453    * All subjects in a composite group are effective members.
1454    * 
1455    * <p/>
1456    * <pre class="eg">
1457    * </pre>
1458    * @param   s     Get membership within this session context.
1459    * @param   g     Composite membership has this group.
1460    * @param   subj  Composite membership has this subject.
1461    * @return  A {@link Membership} object
1462    * @throws  MembershipNotFoundException 
1463    * @throws  SchemaException
1464    * @since   1.0
1465    * @deprecated see overload
1466    */
1467   @Deprecated
1468   public static Membership findCompositeMembership(GrouperSession s, Group g, Subject subj)
1469       throws  MembershipNotFoundException, SchemaException {
1470     
1471     return findCompositeMembership(s, g, subj, true);
1472     
1473   }
1474 
1475   /**
1476    * Return the composite membership if it exists. 
1477    *
1478    * A composite group is composed of two groups and a set operator 
1479    * (stored in grouper_composites table)
1480    * (e.g. union, intersection, etc).  A composite group has no immediate members.
1481    * All subjects in a composite group are effective members.
1482    * 
1483    * <p/>
1484    * <pre class="eg">
1485    * </pre>
1486    * @param   s     Get membership within this session context.
1487    * @param   g     Composite membership has this group.
1488    * @param   subj  Composite membership has this subject.
1489    * @param   exceptionOnNull 
1490    * @return  A {@link Membership} object
1491    * @throws  MembershipNotFoundException 
1492    * @throws  SchemaException
1493    * @since   1.0
1494    */
1495   public static Membership findCompositeMembership(GrouperSession s, Group g, Subject subj, boolean exceptionOnNull)
1496     throws  MembershipNotFoundException, SchemaException {
1497 
1498     //note, no need for GrouperSession inverse of control
1499      // @filtered  true
1500      // @session   true
1501     GrouperSession.validate(s);
1502     try {
1503       Field       f   = Group.getDefaultList();
1504       Member      m   = MemberFinder.findBySubject(s, subj, true);
1505       Membership  ms  = GrouperDAOFactory.getFactory().getMembership().findByGroupOwnerAndMemberAndFieldAndType( 
1506           g.getUuid(), m.getUuid(), f, MembershipType.COMPOSITE.getTypeString(), true, true);
1507       PrivilegeHelper.dispatch( s, ms.getOwnerGroup(), s.getSubject(), f.getReadPriv() );
1508       return ms;
1509     } catch (MembershipNotFoundException mnfe)  {
1510       if (exceptionOnNull) {
1511         throw mnfe;
1512       }
1513       return null;
1514     } catch (InsufficientPrivilegeException eIP)  {
1515       if (exceptionOnNull) {
1516         throw new MembershipNotFoundException(eIP.getMessage(), eIP);
1517       }
1518       return null;
1519     }
1520   }
1521 
1522   /**
1523    * Return effective memberships.  
1524    * 
1525    * An effective member has an indirect membership to a group
1526    * (e.g. in a group within a group).  All subjects in a 
1527    * composite group are effective members (since the composite 
1528    * group has two groups and a set operator and no other immediate 
1529    * members).  Note that a member can have an immediate membership 
1530    * and an effective membership.
1531    * 
1532    * <p/>
1533    * <pre class="eg">
1534    * </pre>
1535    * @param   s     Get membership within this session context.
1536    * @param   g     Effective membership has this group.
1537    * @param   subj  Effective membership has this subject.
1538    * @param   f     Effective membership has this list.
1539    * @param   via   Effective membership has this via group.
1540    * @param   depth Effective membership has this depth.
1541    * @return  A set of {@link Membership} objects.
1542    * @throws  MembershipNotFoundException
1543    * @throws  SchemaException
1544    */
1545   public static Set<Membership> findEffectiveMemberships(
1546     GrouperSession s, Group/internet2/middleware/grouper/Group.html#Group">Group g, Subject subj, Field f, Group via, int depth
1547   )
1548     throws  MembershipNotFoundException,
1549             SchemaException
1550   {
1551     //note, no need for GrouperSession inverse of control
1552      // @filtered  true
1553      // @session   true
1554     GrouperSession.validate(s);
1555     Set mships = new LinkedHashSet();
1556     Member m = MemberFinder.findBySubject(s, subj, true);
1557     try {
1558       PrivilegeHelper.dispatch( s, g, s.getSubject(), f.getReadPriv() );
1559       Iterator  it    = GrouperDAOFactory.getFactory().getMembership().findAllEffectiveByGroupOwner(
1560         g.getUuid(), m.getUuid(), f, via.getUuid(), depth, true
1561       ).iterator();
1562       Membership eff;
1563       while (it.hasNext()) {
1564         eff = (Membership) it.next();
1565         mships.add(eff);
1566       }
1567     }
1568     catch (InsufficientPrivilegeException eIP) {
1569       // ??? ignore
1570     }
1571     return mships;
1572   } // public static Membership findEffectiveMembership(s, g, subj, f, via, depth)
1573 
1574 
1575   /**
1576    * Return the immediate membership if it exists.  
1577    * 
1578    * An immediate member is directly assigned to a group.
1579    * A composite group has no immediate members.  Note that a 
1580    * member can have 0 to 1 immediate memberships
1581    * to a single group, and 0 to many effective memberships to a group.
1582    * A group can have potentially unlimited effective 
1583    * memberships
1584    * 
1585    * <p/>
1586    * <pre class="eg">
1587    * </pre>
1588    * @param   s     Get membership within this session context.
1589    * @param   g     Immediate membership has this group.
1590    * @param   subj  Immediate membership has this subject.
1591    * @param   f     Immediate membership has this list.
1592    * @return  A {@link Membership} object
1593    * @throws  MembershipNotFoundException 
1594    * @throws  SchemaException
1595    * @deprecated see overload
1596    */
1597   @Deprecated
1598   public static Membership findImmediateMembership(
1599     GrouperSession s, Group g, Subject subj, Field f
1600     ) throws  MembershipNotFoundException, SchemaException {
1601     return findImmediateMembership(s, g, subj, f, true);
1602   }
1603 
1604   /**
1605    * Return the immediate membership if it exists.  
1606    * 
1607    * An immediate member is directly assigned to a group.
1608    * A composite group has no immediate members.  Note that a 
1609    * member can have 0 to 1 immediate memberships
1610    * to a single group, and 0 to many effective memberships to a group.
1611    * A group can have potentially unlimited effective 
1612    * memberships
1613    * 
1614    * <p/>
1615    * <pre class="eg">
1616    * </pre>
1617    * @param   s     Get membership within this session context.
1618    * @param   g     Immediate membership has this group.
1619    * @param   subj  Immediate membership has this subject.
1620    * @param   f     Immediate membership has this list.
1621    * @param exceptionIfNotFound
1622    * @return  A {@link Membership} object
1623    * @throws  MembershipNotFoundException 
1624    * @throws  SchemaException
1625    */
1626   public static Membership findImmediateMembership(
1627     GrouperSession s, Group g, Subject subj, boolean exceptionIfNotFound) 
1628       throws  MembershipNotFoundException, SchemaException {
1629     return findImmediateMembership(s, g, subj, Group.getDefaultList(), exceptionIfNotFound);
1630   }
1631 
1632   /**
1633    * Return the immediate membership if it exists.  
1634    * 
1635    * An immediate member is directly assigned to a group.
1636    * A composite group has no immediate members.  Note that a 
1637    * member can have 0 to 1 immediate memberships
1638    * to a single group, and 0 to many effective memberships to a group.
1639    * A group can have potentially unlimited effective 
1640    * memberships
1641    * 
1642    * <p/>
1643    * <pre class="eg">
1644    * </pre>
1645    * @param   s     Get membership within this session context.
1646    * @param   g     Immediate membership has this group.
1647    * @param   subj  Immediate membership has this subject.
1648    * @param   f     Immediate membership has this list.
1649    * @param exceptionIfNotFound
1650    * @return  A {@link Membership} object
1651    * @throws  MembershipNotFoundException 
1652    * @throws  SchemaException
1653    */
1654   public static Membership findImmediateMembership(
1655     GrouperSession s, Group g, Subject subj, Field f, boolean exceptionIfNotFound
1656   ) throws  MembershipNotFoundException, SchemaException {
1657     //note, no need for GrouperSession inverse of control
1658     // @filtered  true
1659     // @session   true
1660     GrouperSession.validate(s);
1661     try {
1662       Member      m   = MemberFinder.findBySubject(s, subj, true);
1663       Membership  ms  = GrouperDAOFactory.getFactory().getMembership().findByGroupOwnerAndMemberAndFieldAndType( 
1664           g.getUuid(), m.getUuid(), f, MembershipType.IMMEDIATE.getTypeString(), true, true);
1665       PrivilegeHelper.dispatch( s, ms.getOwnerGroup(), s.getSubject(), f.getReadPriv() );
1666       return ms;
1667     } catch (MembershipNotFoundException mnfe)         {
1668       if (exceptionIfNotFound) {
1669         throw mnfe;
1670       }
1671       return null;
1672     } catch (GroupNotFoundException eGNF)         {
1673       //not sure why this should happen in a non-corrupt db
1674       if (exceptionIfNotFound) {
1675         throw new MembershipNotFoundException(eGNF.getMessage(), eGNF);
1676       }
1677       return null;
1678     } catch (InsufficientPrivilegeException eIP)  {
1679       if (exceptionIfNotFound) {
1680         throw new MembershipNotFoundException(eIP.getMessage(), eIP);
1681       }
1682       return null;
1683     }
1684   }
1685 
1686 
1687   /**
1688    * Return the immediate membership if it exists.  
1689    * 
1690    * An immediate member is directly assigned to an attributeDef.
1691    * An attributeDef can have potentially unlimited effective 
1692    * memberships
1693    * 
1694    * <p/>
1695    * <pre class="eg">
1696    * </pre>
1697    * @param   s     Get membership within this session context.
1698    * @param    SchemaException     Immediate membership has this attribute def.
1699    * @param   subj  Immediate membership has this subject.
1700    * @param   f     Immediate membership has this list.
1701    * @param exceptionIfNotFound
1702    * @return  A {@link Membership} object
1703    * @throws  MembershipNotFoundException 
1704    * @throws  SchemaException
1705    */
1706   public static Membership findImmediateMembership(
1707     GrouperSession s, AttributeDef attributeDef, Subject subj, Field f, boolean exceptionIfNotFound
1708   ) throws  MembershipNotFoundException, SchemaException {
1709     //note, no need for GrouperSession inverse of control
1710     // @filtered  true
1711     // @session   true
1712     GrouperSession.validate(s);
1713     try {
1714       Member      m   = MemberFinder.findBySubject(s, subj, true);
1715       Membership  ms  = GrouperDAOFactory.getFactory().getMembership().findByAttrDefOwnerAndMemberAndFieldAndType(
1716           attributeDef.getUuid(), m.getUuid(), f, MembershipType.IMMEDIATE.getTypeString(), true, true);
1717       PrivilegeHelper.dispatch( s, ms.getOwnerAttributeDef(), s.getSubject(), f.getReadPriv() );
1718       return ms;
1719     } catch (MembershipNotFoundException mnfe)         {
1720       if (exceptionIfNotFound) {
1721         throw mnfe;
1722       }
1723       return null;
1724     } catch (AttributeDefNotFoundException eGNF)         {
1725       //not sure why this should happen in a non-corrupt db
1726       if (exceptionIfNotFound) {
1727         throw new MembershipNotFoundException(eGNF.getMessage(), eGNF);
1728       }
1729       return null;
1730     } catch (InsufficientPrivilegeException eIP)  {
1731       if (exceptionIfNotFound) {
1732         throw new MembershipNotFoundException(eIP.getMessage(), eIP);
1733       }
1734       return null;
1735     }
1736   }
1737 
1738   /**
1739    * <p>Grouper internal method only</p>
1740    * @param dto
1741    * @return set of memberships
1742    */
1743   public static Set<Membership> internal_findAllChildrenNoPriv(Membership dto) {
1744     Set           children  = new LinkedHashSet();
1745     Membership child;
1746     Iterator      it        = GrouperDAOFactory.getFactory().getMembership().findAllChildMemberships(dto, true).iterator();
1747     while (it.hasNext()) {
1748       child = (Membership) it.next();
1749       children.addAll( internal_findAllChildrenNoPriv(child) );
1750       children.add(child);
1751     }
1752     return children;
1753   } // protected static Set internal_findAllChildrenNoPriv(dto)
1754   
1755   /** 
1756    * @param group 
1757    * @param field 
1758    * @return  A set of all <code>Member</code>'s in <i>group</i>'s list <i>field</i>.
1759    * @throws  IllegalArgumentException if any parameter is null.
1760    * @since   1.2.1
1761    */
1762   public static Set<Member> findMembers(Group group, Field field)
1763     throws  IllegalArgumentException {
1764     return findMembers(group, field, null);
1765   }
1766 
1767   /** 
1768    * @param group 
1769    * @param field 
1770    * @param queryOptions 
1771    * @return  A set of all <code>Member</code>'s in <i>group</i>'s list <i>field</i>.
1772    * @throws  IllegalArgumentException if any parameter is null.
1773    * @since   1.2.1
1774    */
1775   public static Set<Member> findMembers(Group group, Field field, QueryOptions queryOptions)
1776     throws  IllegalArgumentException
1777   {
1778     return findMembers(group, field, null, queryOptions);
1779   }
1780   /** 
1781    * @param group 
1782    * @param field 
1783    * @param sources set of sources to retrieve from or null for all
1784    * @param queryOptions 
1785    * @return  A set of all <code>Member</code>'s in <i>group</i>'s list <i>field</i>.
1786    * @throws  IllegalArgumentException if any parameter is null.
1787    * @since   1.2.1
1788    */
1789   public static Set<Member> findMembers(Group group, Field field, Set<Source> sources, QueryOptions queryOptions)
1790     throws  IllegalArgumentException
1791   {
1792     //note, no need for GrouperSession inverse of control
1793     if (group == null) { // TODO 20070814 ParameterHelper
1794       throw new IllegalArgumentException("null Group");
1795     }
1796     if (field == null) { // TODO 20070814 ParameterHelper
1797       throw new IllegalArgumentException("null Field");
1798     }
1799     Set<Member> members = null;
1800     try {
1801       GrouperSession  s   = GrouperSession.staticGrouperSession();
1802       PrivilegeHelper.dispatch( s, group, s.getSubject(), field.getReadPriv() );
1803       members = GrouperDAOFactory.getFactory().getMembership().findAllMembersByGroupOwnerAndField( 
1804           group.getUuid(), field, sources, queryOptions, true);
1805     }
1806     catch (InsufficientPrivilegeException eIP) {
1807       // ignore  
1808     }
1809     catch (SchemaException eSchema) {
1810       String groupName = null;
1811       try {
1812         groupName = group.getName();
1813       } catch (Exception e) {
1814         LOG.error("error getting group name", e);
1815       }
1816       throw new RuntimeException("Error retrieving members for group: " + groupName, eSchema);
1817     }
1818     return members;
1819   } 
1820 
1821   /**
1822    * <p>Grouper internal method only</p>
1823    * @param s
1824    * @param group
1825    * @param f
1826    * @return set of subjects
1827    * @throws GrouperException
1828    */
1829   public static Set<Subject> internal_findGroupSubjects(GrouperSession s, Group group, Field f) 
1830     throws  GrouperException
1831   {
1832     GrouperSession.validate(s);
1833     Set       subjs = new LinkedHashSet();
1834     Iterator  it    = PrivilegeHelper.canViewMemberships(
1835       s, GrouperDAOFactory.getFactory().getMembership().findAllByGroupOwnerAndField(group.getUuid(), f, true)
1836     ).iterator();
1837     try {
1838       while (it.hasNext()) {
1839     	//2007-12-18 Gary Brown
1840         //Instantiating all the Subjects can be very slow. LazySubjects
1841     	//only make expensive calls when necessary - so a client can page 
1842         //results.
1843     	//A partial alternative may have been to always instantiate the Member of
1844     	//a Membership when the latter is created - assuming one query.
1845     	try {
1846     		subjs.add ( new LazySubject((Membership) it.next()) );
1847     	}catch(GrouperException gre) {
1848     		if(gre.getCause() instanceof MemberNotFoundException) {
1849     			throw (MemberNotFoundException) gre.getCause();
1850     		}
1851     		if(gre.getCause() instanceof SubjectNotFoundException) {
1852     			throw (SubjectNotFoundException) gre.getCause();
1853     		}
1854     	}
1855       }
1856     }
1857     catch (MemberNotFoundException eMNF) {
1858       String msg = "internal_findSubjects: " + eMNF.getMessage();
1859       LOG.fatal(msg);
1860       throw new GrouperException(msg, eMNF);
1861     }
1862     catch (SubjectNotFoundException eSNF) {
1863       String msg = "internal_findSubjects: " + eSNF.getMessage();
1864       LOG.fatal(msg);
1865       throw new GrouperException(msg, eSNF);
1866     }
1867     return subjs;
1868   } // public static Set internal_findSubjects(s, o, f)
1869 
1870   /**
1871    * <p>Grouper internal method only</p>
1872    * @param s
1873    * @param attributeDef
1874    * @param f
1875    * @return set of subjects
1876    * @throws GrouperException
1877    */
1878   public static Set<Subject> internal_findAttributeDefSubjectsImmediateOnly(GrouperSession s,
1879       AttributeDef attributeDef, Field f) throws GrouperException {
1880     GrouperSession.validate(s);
1881     Set<Subject> subjs = new LinkedHashSet();
1882     try {
1883       PrivilegeHelper.dispatch(s, attributeDef, s.getSubject(), f.getReadPriv());
1884       Iterator<Member> it = null; 
1885       //TODO 20090919 fix this
1886 //        GrouperDAOFactory.getFactory().getMembership()
1887 //          .findAllMembersByGroupOwnerAndFieldAndType(group.getUuid(), f,
1888 //              MembershipType.IMMEDIATE.getTypeString(), null, true).iterator();
1889 
1890       while (it.hasNext()) {
1891         try {
1892           subjs.add(new LazySubject(it.next()));
1893         } catch (GrouperException gre) {
1894           if (gre.getCause() instanceof MemberNotFoundException) {
1895             throw (MemberNotFoundException) gre.getCause();
1896           }
1897           if (gre.getCause() instanceof SubjectNotFoundException) {
1898             throw (SubjectNotFoundException) gre.getCause();
1899           }
1900         }
1901       }
1902     } catch (MemberNotFoundException eMNF) {
1903       String msg = "internal_findGroupSubjectsImmediateOnly: " + eMNF.getMessage();
1904       LOG.fatal(msg);
1905       throw new GrouperException(msg, eMNF);
1906     } catch (SubjectNotFoundException eSNF) {
1907       String msg = "internal_findGroupSubjectsImmediateOnly: " + eSNF.getMessage();
1908       LOG.fatal(msg);
1909       throw new GrouperException(msg, eSNF);
1910     } catch (InsufficientPrivilegeException e) {
1911       String msg = "internal_findGroupSubjectsImmediateOnly: " + e.getMessage();
1912       LOG.fatal(msg);
1913       throw new GrouperException(msg, e);
1914     } catch (SchemaException e) {
1915       String msg = "internal_findGroupSubjectsImmediateOnly: " + e.getMessage();
1916       LOG.fatal(msg);
1917       throw new GrouperException(msg, e);
1918     }
1919     return subjs;
1920   } 
1921   
1922   /**
1923    * <p>Grouper internal method only</p>
1924    * @param s
1925    * @param stem
1926    * @param f
1927    * @return set of subjects
1928    * @throws GrouperException
1929    */
1930   public static Set<Subject> internal_findStemSubjectsImmediateOnly(GrouperSession s,
1931       Stem stem, Field f) throws GrouperException {
1932     GrouperSession.validate(s);
1933     Set<Subject> subjs = new LinkedHashSet();
1934     try {
1935       PrivilegeHelper.dispatch(s, stem, s.getSubject(), f.getReadPriv());
1936       Iterator<Member> it = GrouperDAOFactory.getFactory().getMembership()
1937           .findAllMembersByStemOwnerAndFieldAndType(stem.getUuid(), f,
1938               MembershipType.IMMEDIATE.getTypeString(), null, true).iterator();
1939 
1940       while (it.hasNext()) {
1941         try {
1942           subjs.add(new LazySubject(it.next()));
1943         } catch (GrouperException gre) {
1944           if (gre.getCause() instanceof MemberNotFoundException) {
1945             throw (MemberNotFoundException) gre.getCause();
1946           }
1947           if (gre.getCause() instanceof SubjectNotFoundException) {
1948             throw (SubjectNotFoundException) gre.getCause();
1949           }
1950         }
1951       }
1952     } catch (MemberNotFoundException eMNF) {
1953       String msg = "internal_findStemSubjectsImmediateOnly: " + eMNF.getMessage();
1954       LOG.fatal(msg);
1955       throw new GrouperException(msg, eMNF);
1956     } catch (SubjectNotFoundException eSNF) {
1957       String msg = "internal_findStemSubjectsImmediateOnly: " + eSNF.getMessage();
1958       LOG.fatal(msg);
1959       throw new GrouperException(msg, eSNF);
1960     } catch (InsufficientPrivilegeException e) {
1961       String msg = "internal_findStemSubjectsImmediateOnly: " + e.getMessage();
1962       LOG.fatal(msg);
1963       throw new GrouperException(msg, e);
1964     } catch (SchemaException e) {
1965       String msg = "internal_findStemSubjectsImmediateOnly: " + e.getMessage();
1966       LOG.fatal(msg);
1967       throw new GrouperException(msg, e);
1968     }
1969     return subjs;
1970   } 
1971   
1972 
1973   /** logger */
1974   private static final Log LOG = GrouperUtil.getLog(MemberFinder.class);
1975 
1976   /**
1977    * <p>Grouper internal method only</p>
1978    * @param s
1979    * @param stem
1980    * @param f
1981    * @return set of subjects
1982    */
1983   public static Set<Subject> internal_findSubjectsStemPriv(GrouperSession s, Stem stem, Field f) {
1984      // @filtered  false
1985      // @session   true 
1986     GrouperSession.validate(s);
1987     Membership mbs;
1988     Set           subjs = new LinkedHashSet();
1989     Iterator      it    = GrouperDAOFactory.getFactory().getMembership().findAllByStemOwnerAndField(stem.getUuid(), f, true).iterator();
1990     while (it.hasNext()) {
1991       mbs = (Membership) it.next();
1992       try {
1993     	  subjs.add ( new LazySubject(mbs) );
1994         //_m = dao.findByUuid( ms.getMemberUuid() );
1995         //subjs.add( SubjectFinder.findById( _m.getSubjectId(), _m.getSubjectTypeId(), _m.getSubjectSourceId() ) );
1996       }
1997       catch (Exception e) {
1998         // @exception MemberNotFoundException
1999         // @exception SubjectNotFoundException
2000         LOG.error(E.MSF_FINDSUBJECTS + e.getMessage());
2001       }
2002     }
2003     return subjs;
2004   } // public static Set internal_findSubjectsNoPriv(s, o, f)
2005 
2006   /**
2007    * <p>Grouper internal method only</p>
2008    * @param s
2009    * @param g
2010    * @param f
2011    * @param type
2012    * @return set of members
2013    */
2014   public static Set<Member> internal_findMembersByType(GrouperSession s, Group g, Field f, String type) {
2015     GrouperSession.validate(s);
2016     Set         members = new LinkedHashSet();
2017     Membership  ms;
2018     Iterator    it      = internal_findAllByGroupOwnerAndFieldAndType(s, g, f, type).iterator();
2019     while (it.hasNext()) {
2020       ms = (Membership) it.next();
2021       try {
2022         members.add(ms.getMember());
2023       }
2024       catch (MemberNotFoundException eMNF) {
2025         // Ignore
2026       }
2027     }
2028     return members;
2029   } // public static Set internal_findMembersByType(s, g, f, type)
2030 
2031   /**
2032    * query options for member.  must include paging.  if sorting then sort by member
2033    */
2034   private QueryOptions queryOptionsForMember;
2035 
2036   /**
2037    * query options for membership.  must include paging and sorting
2038    */
2039   private QueryOptions queryOptionsForMembership;
2040   
2041   /**
2042    * if paging for member, then also filter for member
2043    */
2044   private String scopeForMember;
2045 
2046   /**
2047    * if paging for member, then also filter for member
2048    * @param theFilterForMember
2049    * @return this for chaining
2050    */
2051   public MembershipFinder assignScopeForMember(String theFilterForMember) {
2052     this.scopeForMember = theFilterForMember;
2053     return this;
2054   }
2055   
2056   /**
2057    * if the scope for member has spaces in it, then split by whitespace, and find results that contain all of the scope strings
2058    */
2059   private boolean splitScopeForMember;
2060 
2061   /**
2062    * query options for group.  must include paging.  if sorting then sort by group
2063    */
2064   private QueryOptions queryOptionsForGroup;
2065 
2066   /**
2067    * query options for group.  must include paging.  if sorting then sort by group
2068    * @param theQueryOptionsForGroup
2069    * @return this for chaining
2070    */
2071   public MembershipFinder assignQueryOptionsForGroup(QueryOptions theQueryOptionsForGroup) {
2072     this.queryOptionsForGroup = theQueryOptionsForGroup;
2073     return this;
2074   }
2075   
2076   /**
2077    * if the scope for group has spaces in it, then split by whitespace, and find results that contain all of the scope strings
2078    */
2079   private boolean splitScopeForGroup;
2080 
2081   /**
2082    * return memberships where the group has this field, note, it will return all the memberships for those groups
2083    */
2084   private boolean hasMembershipTypeForGroup;
2085 
2086   /**
2087    * if paging for group, then also filter for group
2088    */
2089   private String scopeForGroup;
2090   
2091   /**
2092    * return memberships where the stem has this field, note, it will return all the memberships for those stems 
2093    */
2094   private boolean hasFieldForStem;
2095 
2096   /**
2097    * return memberships where the stem has this field, note, it will return all the memberships for those stems 
2098    * @param theHasFieldForStem
2099    * @return this for chaining
2100    */
2101   public MembershipFinder assignHasFieldForStem(boolean theHasFieldForStem) {
2102     this.hasFieldForStem = theHasFieldForStem;
2103     return this;
2104   }
2105   
2106   /**
2107    * return memberships where the stem has this field, note, it will return all the memberships for those stems
2108    */
2109   private boolean hasMembershipTypeForStem;
2110   
2111   /**
2112    * return memberships where the stem has this field, note, it will return all the memberships for those stems
2113    * @return this for chaining
2114    */
2115   public MembershipFinder assignHasMembershipTypeForStem(boolean theHasMembershipTypeForStem) {
2116     this.hasMembershipTypeForStem = theHasMembershipTypeForStem;
2117     return this;
2118   }
2119   
2120   /**
2121    * query options for stem.  must include paging.  if sorting then sort by stem
2122    */
2123   private QueryOptions queryOptionsForStem;
2124 
2125   /**
2126    * query options for stem.  must include paging.  if sorting then sort by stem
2127    * @param theQueryOptionsForStem
2128    * @return this for chaining
2129    */
2130   public MembershipFinder assignQueryOptionsForStem(QueryOptions theQueryOptionsForStem) {
2131     this.queryOptionsForStem = theQueryOptionsForStem;
2132     return this;
2133   }
2134   
2135   /**
2136    * if paging for stem, then also filter for stem
2137    */
2138   private String scopeForStem;
2139 
2140   /**
2141    * if paging for stem, then also filter for stem
2142    * @param theScopeForStem
2143    * @return this for chaining
2144    */
2145   public MembershipFinder assignScopeForStem(String theScopeForStem) {
2146     this.scopeForStem = theScopeForStem;
2147     return this;
2148   }
2149   
2150   /**
2151    * if the scope for stem has spaces in it, then split by whitespace, and find results that contain all of the scope strings
2152    */
2153   private boolean splitScopeForStem;
2154 
2155   /** 
2156    * return memberships where the attributeDef has this field, note, it will return all the memberships for those attributeDefs 
2157    */
2158   private boolean hasFieldForAttributeDef;
2159 
2160   /**
2161    * return memberships where the attributeDef has this field, note, it will return all the memberships for those attributeDefs 
2162    * @param theHasFieldForAttributeDef
2163    * @return this for chaining
2164    */
2165   public MembershipFinder assignHasFieldForAttributeDef(boolean theHasFieldForAttributeDef) {
2166     this.hasFieldForAttributeDef = theHasFieldForAttributeDef;
2167     return this;
2168   }
2169   
2170   /**
2171    * return memberships where the attributeDef has this field, note, it will return all the memberships for those attributeDefs
2172    */
2173   private boolean hasMembershipTypeForAttributeDef;
2174 
2175   /**
2176    * return memberships where the attributeDef has this field, note, it will return all the memberships for those attributeDefs
2177    * @param theHasMembershipTypeForAttributeDef
2178    * @return this for chaining
2179    */
2180   public MembershipFinder assignHasMembershipTypeForAttributeDef(boolean theHasMembershipTypeForAttributeDef) {
2181     this.hasMembershipTypeForAttributeDef = theHasMembershipTypeForAttributeDef;
2182     return this;
2183   }
2184   
2185   /**
2186    * query options for attributeDef.  must include paging.  if sorting then sort by attributeDef
2187    */
2188   private QueryOptions queryOptionsForAttributeDef;
2189 
2190   /**
2191    * query options for attributeDef.  must include paging.  if sorting then sort by attributeDef
2192    * @param theQueryOptionsForAttributeDef
2193    * @return this for chaining
2194    */
2195   public MembershipFinder assignQueryOptionsForAttributeDef(QueryOptions theQueryOptionsForAttributeDef) {
2196     this.queryOptionsForAttributeDef = theQueryOptionsForAttributeDef;
2197     return this;
2198   }
2199   
2200   /**
2201    * if paging for attributeDef, then also filter for group
2202    */
2203   private String scopeForAttributeDef;
2204 
2205   /**
2206    * if paging for attributeDef, then also filter for group
2207    * @param theScopeForAttributeDef
2208    * @return this for chaining
2209    */
2210   public MembershipFinder assignScopeForAttributeDef(String theScopeForAttributeDef) {
2211     this.scopeForAttributeDef = theScopeForAttributeDef;
2212     return this;
2213   }
2214   
2215   /**
2216    * if the scope for attributeDef has spaces in it, then split by whitespace, and find results that contain all of the scope strings
2217    */
2218   private boolean splitScopeForAttributeDef;
2219 
2220   /**
2221    * if the scope for attributeDef has spaces in it, then split by whitespace, and find results that contain all of the scope strings
2222    * @param theSplitScopeForAttributeDef
2223    * @return this
2224    */
2225   public MembershipFinder assignSplitScopeForAttributeDef(boolean theSplitScopeForAttributeDef) {
2226     this.splitScopeForAttributeDef = theSplitScopeForAttributeDef;
2227     return this;
2228   }
2229   
2230   /**
2231    * if the scope for stem has spaces in it, then split by whitespace, and find results that contain all of the scope strings
2232    * @param theSplitScopeForStem
2233    * @return this for chaining
2234    */
2235   public MembershipFinder assignSplitScopeForStem(boolean theSplitScopeForStem) {
2236     this.splitScopeForStem = theSplitScopeForStem;
2237     return this;
2238   }
2239   
2240   /**
2241    * if paging for group, then also filter for member
2242    * @param theScopeForGroup
2243    * @return this for chaining
2244    */
2245   public MembershipFinder assignScopeForGroup(String theScopeForGroup) {
2246     this.scopeForGroup = theScopeForGroup;
2247     return this;
2248   }
2249   
2250   /**
2251    * return memberships where the group has this field, note, it will return all the memberships for those groups
2252    * @param theHasMembershipTypeForGroup
2253    * @return this for chaining
2254    */
2255   public MembershipFinder assignHasMembershipTypeForGroup(boolean theHasMembershipTypeForGroup) {
2256     this.hasMembershipTypeForGroup = theHasMembershipTypeForGroup;
2257     return this;
2258   }
2259   
2260   /**
2261    * if the scope for group has spaces in it, then split by whitespace, and find results that contain all of the scope strings
2262    * @param theSplitScopeForGroup
2263    * @return this for chaining
2264    */
2265   public MembershipFinder assignSplitScopeForGroup(boolean theSplitScopeForGroup) {
2266     this.splitScopeForGroup = theSplitScopeForGroup;
2267     return this;
2268   }
2269   
2270   /**
2271    * if the scope for member has spaces in it, then split by whitespace, and find results that contain all of the scope strings
2272    * @param theSplitScopeForMember
2273    * @return if splitting scope for member
2274    */
2275   public MembershipFinder assignSplitScopeForMember(boolean theSplitScopeForMember) {
2276     this.splitScopeForMember = theSplitScopeForMember;
2277     return this;
2278   }
2279 
2280   /**
2281    * 
2282    * @param theQueryOptions
2283    * @return
2284    */
2285   public MembershipFinder assignQueryOptionsForMember(QueryOptions theQueryOptions) {
2286     this.queryOptionsForMember = theQueryOptions;
2287     return this;
2288   }
2289   
2290   /**
2291    * 
2292    * @param theQueryOptions
2293    * @return
2294    */
2295   public MembershipFinder assignQueryOptionsForMembership(QueryOptions theQueryOptions) {
2296     this.queryOptionsForMembership = theQueryOptions;
2297     return this;
2298   }
2299   
2300   /**
2301    * assign a collection of fields to look for the user has for groups
2302    * @param thePrivilegesTheUserHas
2303    * @return this for chaining
2304    */
2305   public MembershipFinder assignPrivilegesTheUserHas(Collection<Privilege> thePrivilegesTheUserHas) {
2306     this.privilegesTheUserHas = thePrivilegesTheUserHas;
2307     return this;
2308   }
2309 
2310   /**
2311    * assign a collection of fields to look for the user has for groups
2312    * @param thePrivilegeNamesOfPrivilegesTheUserHas
2313    * @return this for chaining
2314    */
2315   public MembershipFinder assignPrivilegesTheUserHasByName(Collection<String> thePrivilegeNamesOfPrivilegesTheUserHas) {
2316     
2317     this.privilegesTheUserHas = GrouperUtil.nonNull(Privilege.convertNamesToPrivileges(thePrivilegeNamesOfPrivilegesTheUserHas));
2318       
2319     return this;
2320   }
2321 
2322   /**
2323    * <p>Grouper internal method only</p>
2324    * @param s
2325    * @param d
2326    * @param f
2327    * @return set of memberships
2328    * @throws QueryException
2329    */
2330   public static Set<Membership> internal_findAllByCreatedAfter(GrouperSession s, Date d, Field f) 
2331     throws QueryException 
2332   {
2333     //note, no need for GrouperSession inverse of control
2334     // @filtered  false
2335     // @session   true
2336     Set         mships  = new LinkedHashSet();
2337     Membership  ms;
2338     Iterator    it      = GrouperDAOFactory.getFactory().getMembership().findAllByCreatedAfter(d, f, true).iterator();
2339     while (it.hasNext()) {
2340       ms = (Membership) it.next();
2341       mships.add(ms);
2342     }
2343     return mships;
2344   } 
2345 
2346   /**
2347    * <p>Grouper internal method only</p>
2348    * @param s
2349    * @param d
2350    * @param f
2351    * @return set of memberships
2352    * @throws QueryException
2353    */
2354   public static Set<Membership> internal_findAllByCreatedBefore(GrouperSession s, Date d, Field f) 
2355     throws QueryException {
2356     //note, no need for GrouperSession inverse of control
2357     // @filtered  false
2358     // @session   true
2359     Set         mships  = new LinkedHashSet();
2360     Membership  ms;
2361     Iterator    it      = GrouperDAOFactory.getFactory().getMembership().findAllByCreatedBefore(d, f, true).iterator();
2362     while (it.hasNext()) {
2363       ms = (Membership) it.next();
2364       mships.add(ms);
2365     }
2366     return mships;
2367   } // public static Set internal_findAllByCreatedBefore(s, d, f)
2368 
2369   /**
2370    * <p>Grouper internal method only</p>
2371    * @param s
2372    * @param groupOwner
2373    * @param f
2374    * @param type
2375    * @return set of memberships
2376    */
2377   public static Set<Membership> internal_findAllByGroupOwnerAndFieldAndType(GrouperSession s, Group groupOwner, Field f, String type) {
2378      // @filtered  true
2379      // @session   true
2380     GrouperSession.validate(s);
2381     return PrivilegeHelper.canViewMemberships(
2382       s, GrouperDAOFactory.getFactory().getMembership().findAllByGroupOwnerAndFieldAndType(groupOwner.getUuid(), f, type, true)
2383     );
2384   } // public static Set internal_findAllByOwnerAndFieldAndType(s, o, f, type)
2385 
2386   /**
2387    * <p>Grouper internal method only</p>
2388    * @param s
2389    * @param m
2390    * @param f
2391    * @return set of memberships
2392    */
2393   public static Set<Membership> internal_findAllEffectiveByMemberAndField(
2394     GrouperSession s, Member m, Field f
2395   ) 
2396   {
2397     // @filtered  true
2398     // @session   true
2399     GrouperSession.validate(s);
2400     return PrivilegeHelper.canViewMemberships( 
2401       s, GrouperDAOFactory.getFactory().getMembership().findAllEffectiveByMemberAndField(m.getUuid(), f, true) 
2402     );
2403   } // public static Set internal_findAllEffectiveByMemberAndField(s, m, f)
2404 
2405   /**
2406    * <p>Grouper internal method only</p>
2407    * @param s
2408    * @param m
2409    * @param f
2410    * @return set of memberships
2411    */
2412   public static Set<Membership> internal_findAllImmediateByMemberAndField(GrouperSession s, Member m, Field f) {
2413     return internal_findAllImmediateByMemberAndField(s, m, f, true);
2414   } 
2415 
2416   /**
2417    * <p>Grouper internal method only</p>
2418    * @param s
2419    * @param m
2420    * @param f
2421    * @param enabledOnly 
2422    * @return set of memberships
2423    */
2424   public static Set<Membership> internal_findAllImmediateByMemberAndField(GrouperSession s, Member m, Field f, boolean enabledOnly) {
2425     // @filtered  true
2426     // @session   true
2427     GrouperSession.validate(s);
2428     return PrivilegeHelper.canViewMemberships( 
2429       s, GrouperDAOFactory.getFactory().getMembership().findAllImmediateByMemberAndField(m.getUuid(), f, enabledOnly) 
2430     );
2431   } 
2432   
2433   /**
2434    * <p>Grouper internal method only</p>
2435    * @param s
2436    * @param m
2437    * @param f
2438    * @return set of memberships
2439    */
2440   public static Set<Membership> internal_findAllNonImmediateByMemberAndField(GrouperSession s, Member m, Field f) {
2441     // @filtered  true
2442     // @session   true
2443     GrouperSession.validate(s);
2444     return PrivilegeHelper.canViewMemberships( 
2445       s, GrouperDAOFactory.getFactory().getMembership().findAllNonImmediateByMemberAndField(m.getUuid(), f, true) 
2446     );
2447   } 
2448 
2449   /**
2450    * <p>Grouper internal method only</p>
2451    * @param s
2452    * @param m
2453    * @param f
2454    * @return set of memberships
2455    */
2456   public static Set<Membership> internal_findMemberships(GrouperSession s, Member m, Field f) {
2457      // @filtered  true
2458      // @session   true
2459     GrouperSession.validate(s);
2460     MembershipDAO dao     = GrouperDAOFactory.getFactory().getMembership();
2461     return dao.findMembershipsByMemberAndFieldSecure(s, m.getUuid(), f, true);
2462   } // public static Set internal_findMemberships(s, m, f)
2463 
2464   /**
2465    * <p>Grouper internal method only</p>
2466    * @param start
2467    * @param pageSize
2468    * @param group
2469    * @param field
2470    * @param sortLimit
2471    * @param numberOfRecords (pass in array of size one to get the result size back)
2472    * @return the set of membership
2473    * @throws SchemaException
2474    */
2475   public static Set<Membership> internal_findAllImmediateByGroupAndFieldAndPage(Group group,
2476       Field field, int start, int pageSize, int sortLimit, int[] numberOfRecords) throws SchemaException {
2477     Set<Membership> allChildren;
2478     //get the size
2479     QueryOptionsl/dao/QueryOptions.html#QueryOptions">QueryOptions queryOptions = new QueryOptions().retrieveCount(true).retrieveResults(false);
2480     group.getImmediateMembers(field, queryOptions);
2481     int totalSize = queryOptions.getCount().intValue();
2482     
2483     if (GrouperUtil.length(numberOfRecords) > 0) {
2484       numberOfRecords[0] = totalSize;
2485     }
2486 
2487     //if there are less than the sort limit, then just get all, no problem
2488     if (totalSize <= sortLimit) {
2489       allChildren = group.getImmediateMemberships(field);
2490     } else {
2491       //get the members that we will display, sorted by subjectId
2492       //TODO in 1.5 sort by subject sort string when under a certain limit, huge resultsets
2493       //are slow for mysql
2494       
2495       QueryPagingnal/dao/QueryPaging.html#QueryPaging">QueryPaging queryPaging = new QueryPaging();
2496       queryPaging.setPageSize(pageSize);
2497       queryPaging.setFirstIndexOnPage(start);
2498 
2499       //.sortAsc("m.subjectIdDb")   this kills performance
2500       queryOptions = new QueryOptions().paging(queryPaging);
2501 
2502       Set<Member> members = group.getImmediateMembers(field, queryOptions);
2503       allChildren = group.getImmediateMemberships(field, members);
2504     }
2505     return allChildren;
2506   }
2507 
2508   /**
2509    * <p>Grouper internal method only</p>
2510    * @param start
2511    * @param pageSize
2512    * @param group
2513    * @param sortLimit
2514    * @param numberOfRecords (pass in array of size one to get the result size back)
2515    * @return the set of membership
2516    * @throws SchemaException
2517    */
2518   public static Set<Membership> internal_findAllCompositeByGroupAndPage(Group group,
2519       int start, int pageSize, int sortLimit, int[] numberOfRecords) throws SchemaException {
2520     Set<Membership> allChildren;
2521     //get the size
2522     QueryOptionsl/dao/QueryOptions.html#QueryOptions">QueryOptions queryOptions = new QueryOptions().retrieveCount(true).retrieveResults(false);
2523     group.getCompositeMembers(queryOptions);
2524     int totalSize = queryOptions.getCount().intValue();
2525     
2526     if (GrouperUtil.length(numberOfRecords) > 0) {
2527       numberOfRecords[0] = totalSize;
2528     }
2529 
2530     //if there are less than the sort limit, then just get all, no problem
2531     if (totalSize <= sortLimit) {
2532       allChildren = group.getCompositeMemberships();
2533     } else {
2534       //get the members that we will display, sorted by subjectId
2535       //TODO in 1.5 sort by subject sort string when under a certain limit, huge resultsets
2536       //are slow for mysql
2537       
2538       QueryPagingnal/dao/QueryPaging.html#QueryPaging">QueryPaging queryPaging = new QueryPaging();
2539       queryPaging.setPageSize(pageSize);
2540       queryPaging.setFirstIndexOnPage(start);
2541 
2542       //.sortAsc("m.subjectIdDb")   this kills performance
2543       queryOptions = new QueryOptions().paging(queryPaging);
2544 
2545       Set<Member> members = group.getCompositeMembers(queryOptions);
2546       allChildren = group.getCompositeMemberships(members);
2547     }
2548     return allChildren;
2549   }
2550 
2551   /**
2552    * <p>Grouper internal method only</p>
2553    * @param start
2554    * @param pageSize
2555    * @param group
2556    * @param field
2557    * @param sortLimit
2558    * @param numberOfRecords (pass in array of size one to get the result size back)
2559    * @return the set of membership
2560    * @throws SchemaException
2561    */
2562   public static Set<Membership> internal_findAllEffectiveByGroupAndFieldAndPage(Group group,
2563       Field field, int start, int pageSize, int sortLimit, int[] numberOfRecords) throws SchemaException {
2564     Set<Membership> allChildren;
2565     //get the size
2566     QueryOptionsl/dao/QueryOptions.html#QueryOptions">QueryOptions queryOptions = new QueryOptions().retrieveCount(true).retrieveResults(false);
2567     group.getEffectiveMembers(field, queryOptions);
2568     int totalSize = queryOptions.getCount().intValue();
2569     
2570     if (GrouperUtil.length(numberOfRecords) > 0) {
2571       numberOfRecords[0] = totalSize;
2572     }
2573 
2574     //if there are less than the sort limit, then just get all, no problem
2575     if (totalSize <= sortLimit) {
2576       allChildren = group.getEffectiveMemberships(field);
2577     } else {
2578       //get the members that we will display, sorted by subjectId
2579       //TODO in 1.5 sort by subject sort string when under a certain limit, huge resultsets
2580       //are slow for mysql
2581       
2582       QueryPagingnal/dao/QueryPaging.html#QueryPaging">QueryPaging queryPaging = new QueryPaging();
2583       queryPaging.setPageSize(pageSize);
2584       queryPaging.setFirstIndexOnPage(start);
2585 
2586       //.sortAsc("m.subjectIdDb")   this kills performance
2587       queryOptions = new QueryOptions().paging(queryPaging);
2588 
2589       Set<Member> members = group.getEffectiveMembers(field, queryOptions);
2590       allChildren = group.getEffectiveMemberships(field, members);
2591     }
2592     return allChildren;
2593   }
2594 
2595   /**
2596    * <p>Grouper internal method only</p>
2597    * @param start
2598    * @param pageSize
2599    * @param group
2600    * @param field
2601    * @param sortLimit
2602    * @param numberOfRecords (pass in array of size one to get the result size back)
2603    * @return the set of membership
2604    * @throws SchemaException
2605    */
2606   public static Set<Membership> internal_findAllByGroupAndFieldAndPage(Group group,
2607       Field field, int start, int pageSize, int sortLimit, int[] numberOfRecords) throws SchemaException {
2608     Set<Membership> allChildren;
2609     //get the size
2610     QueryOptionsl/dao/QueryOptions.html#QueryOptions">QueryOptions queryOptions = new QueryOptions().retrieveCount(true).retrieveResults(false);
2611     group.getMembers(field, queryOptions);
2612     int totalSize = queryOptions.getCount().intValue();
2613     
2614     if (GrouperUtil.length(numberOfRecords) > 0) {
2615       numberOfRecords[0] = totalSize;
2616     }
2617     
2618     //if there are less than the sort limit, then just get all, no problem
2619     if (totalSize <= sortLimit) {
2620       allChildren = group.getMemberships(field);
2621     } else {
2622       //get the members that we will display, sorted by subjectId
2623       //TODO in 1.5 sort by subject sort string when under a certain limit, huge resultsets
2624       //are slow for mysql
2625       
2626       QueryPagingnal/dao/QueryPaging.html#QueryPaging">QueryPaging queryPaging = new QueryPaging();
2627       queryPaging.setPageSize(pageSize);
2628       queryPaging.setFirstIndexOnPage(start);
2629 
2630       //.sortAsc("m.subjectIdDb")   this kills performance
2631       queryOptions = new QueryOptions().paging(queryPaging);
2632 
2633       Set<Member> members = group.getMembers(field, queryOptions);
2634       allChildren = group.getMemberships(field, members);
2635     }
2636     return allChildren;
2637     }
2638 
2639   /**
2640    * <p>Grouper internal method only</p>
2641    * @param s
2642    * @param attributeDef
2643    * @param f
2644    * @return set of subjects
2645    * @throws GrouperException
2646    */
2647   public static Set<Subject> internal_findAttributeDefSubjects(GrouperSession s, AttributeDef attributeDef, Field f) 
2648     throws  GrouperException {
2649     GrouperSession.validate(s);
2650     Set       subjs = new LinkedHashSet();
2651     Iterator  it    = null;
2652     //TODO 20090919 fix this
2653 //    PrivilegeHelper.canViewAttributeDefs(
2654 //      s, GrouperDAOFactory.getFactory().getMembership().findAllByAttrDefOwnerAndField(attributeDef.getId(), f, true)
2655 //    ).iterator();
2656     try {
2657       while (it.hasNext()) {
2658     	//2007-12-18 Gary Brown
2659         //Instantiating all the Subjects can be very slow. LazySubjects
2660     	//only make expensive calls when necessary - so a client can page 
2661         //results.
2662     	//A partial alternative may have been to always instantiate the Member of
2663     	//a Membership when the latter is created - assuming one query.
2664     	try {
2665     		subjs.add ( new LazySubject((Membership) it.next()) );
2666     	}catch(GrouperException gre) {
2667     		if(gre.getCause() instanceof MemberNotFoundException) {
2668     			throw (MemberNotFoundException) gre.getCause();
2669     		}
2670     		if(gre.getCause() instanceof SubjectNotFoundException) {
2671     			throw (SubjectNotFoundException) gre.getCause();
2672     		}
2673     	}
2674       }
2675     }
2676     catch (MemberNotFoundException eMNF) {
2677       String msg = "internal_findSubjects: " + eMNF.getMessage();
2678       LOG.fatal(msg);
2679       throw new GrouperException(msg, eMNF);
2680     }
2681     catch (SubjectNotFoundException eSNF) {
2682       String msg = "internal_findSubjects: " + eSNF.getMessage();
2683       LOG.fatal(msg);
2684       throw new GrouperException(msg, eSNF);
2685     }
2686     return subjs;
2687   } // public static Set internal_findSubjects(s, o, f)
2688 
2689   /**
2690    * <p>Grouper internal method only</p>
2691    * @param s
2692    * @param group
2693    * @param f
2694    * @return set of subjects
2695    * @throws GrouperException
2696    */
2697   public static Set<Subject> internal_findGroupSubjectsImmediateOnly(GrouperSession s,
2698       Group group, Field f) throws GrouperException {
2699     GrouperSession.validate(s);
2700     Set<Subject> subjs = new LinkedHashSet();
2701     try {
2702       PrivilegeHelper.dispatch(s, group, s.getSubject(), f.getReadPriv());
2703       Iterator<Member> it = GrouperDAOFactory.getFactory().getMembership()
2704           .findAllMembersByGroupOwnerAndFieldAndType(group.getUuid(), f,
2705               MembershipType.IMMEDIATE.getTypeString(), null, true).iterator();
2706   
2707       while (it.hasNext()) {
2708         try {
2709           subjs.add(new LazySubject(it.next()));
2710         } catch (GrouperException gre) {
2711           if (gre.getCause() instanceof MemberNotFoundException) {
2712             throw (MemberNotFoundException) gre.getCause();
2713           }
2714           if (gre.getCause() instanceof SubjectNotFoundException) {
2715             throw (SubjectNotFoundException) gre.getCause();
2716           }
2717         }
2718       }
2719     } catch (MemberNotFoundException eMNF) {
2720       String msg = "internal_findGroupSubjectsImmediateOnly: " + eMNF.getMessage();
2721       LOG.fatal(msg);
2722       throw new GrouperException(msg, eMNF);
2723     } catch (SubjectNotFoundException eSNF) {
2724       String msg = "internal_findGroupSubjectsImmediateOnly: " + eSNF.getMessage();
2725       LOG.fatal(msg);
2726       throw new GrouperException(msg, eSNF);
2727     } catch (InsufficientPrivilegeException e) {
2728       String msg = "internal_findGroupSubjectsImmediateOnly: " + e.getMessage();
2729       LOG.fatal(msg);
2730       throw new GrouperException(msg, e);
2731     } catch (SchemaException e) {
2732       String msg = "internal_findGroupSubjectsImmediateOnly: " + e.getMessage();
2733       LOG.fatal(msg);
2734       throw new GrouperException(msg, e);
2735     }
2736     return subjs;
2737   }
2738 
2739   /**
2740    * Find a membership within the registry by UUID.  This will be either the uuid or immediate uuid.
2741    * Security will be checked to see if the grouper session is allowed to see the membership
2742    * <pre class="eg">
2743    *   Membership membership = MembershipFinder.findByUuid(grouperSession, uuid);
2744    * </pre>
2745    * @param   grouperSession     Find membership within this session context.
2746    * @param   uuid  UUID of membership to find.
2747    * @param exceptionIfNotFound true if exception if not found
2748    * @param enabledOnly true for enabled only
2749    * @return  A {@link Membership}
2750    * @throws MembershipNotFoundException if not found an exceptionIfNotFound is true
2751    */
2752   public static Membership findByUuid(GrouperSession grouperSession, String uuid, boolean exceptionIfNotFound, boolean enabledOnly) 
2753       throws MembershipNotFoundException {
2754     //note, no need for GrouperSession inverse of control
2755     GrouperSession.validate(grouperSession);
2756     Membership membership = GrouperDAOFactory.getFactory().getMembership().findByUuid(uuid, exceptionIfNotFound, enabledOnly);
2757     if (membership == null) {
2758       if(exceptionIfNotFound) {
2759         throw new MembershipNotFoundException("Not allowed to view membership: " + uuid);
2760       }
2761       return null;
2762     }
2763     if ( PrivilegeHelper.canViewMembership( grouperSession.internal_getRootSession(), membership ) ) {
2764       return membership;
2765     }   
2766     return null;
2767   }
2768   
2769   /**
2770    * Find all the membership subject containers for a given subject
2771    * @param grouperSession
2772    * @param subject
2773    * @return
2774    */
2775   public static Set<MembershipSubjectContainer> findAllImmediateMemberhipSubjectContainers(GrouperSession grouperSession, Subject subject) {
2776     
2777     Set<MembershipSubjectContainer> result = new HashSet<MembershipSubjectContainer>();
2778     GrouperSession.validate(grouperSession);
2779     
2780     for (FieldTypeieldType.html#FieldType">FieldType fieldType : new FieldType[] {FieldType.LIST, FieldType.ACCESS, FieldType.NAMING, FieldType.ATTRIBUTE_DEF}) {
2781       MembershipResult membershipResult = new MembershipFinder().addSubject(subject)
2782           .assignFieldType(fieldType)
2783           .assignMembershipType(MembershipType.IMMEDIATE).findMembershipResult();
2784       result.addAll(membershipResult.getMembershipSubjectContainers());
2785     }
2786     
2787     return result;
2788   }
2789 } // public class MembershipFinder
2790