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.io.StringWriter;
35  import java.util.Date;
36  import java.util.Iterator;
37  import java.util.LinkedHashSet;
38  import java.util.Set;
39  
40  import org.apache.commons.lang.StringUtils;
41  import org.apache.commons.lang.builder.EqualsBuilder;
42  import org.apache.commons.lang.builder.HashCodeBuilder;
43  import org.apache.commons.lang.builder.ToStringBuilder;
44  import org.apache.commons.lang.builder.ToStringStyle;
45  import org.apache.commons.logging.Log;
46  
47  import edu.internet2.middleware.grouper.cfg.GrouperConfig;
48  import edu.internet2.middleware.grouper.exception.GroupNotFoundException;
49  import edu.internet2.middleware.grouper.group.GroupSet;
50  import edu.internet2.middleware.grouper.hibernate.HibernateSession;
51  import edu.internet2.middleware.grouper.hooks.CompositeHooks;
52  import edu.internet2.middleware.grouper.hooks.beans.HooksCompositeBean;
53  import edu.internet2.middleware.grouper.hooks.logic.GrouperHookType;
54  import edu.internet2.middleware.grouper.hooks.logic.GrouperHooksUtils;
55  import edu.internet2.middleware.grouper.hooks.logic.VetoTypeGrouper;
56  import edu.internet2.middleware.grouper.internal.dao.QueryOptions;
57  import edu.internet2.middleware.grouper.internal.dao.hib3.Hib3GrouperVersioned;
58  import edu.internet2.middleware.grouper.internal.util.Quote;
59  import edu.internet2.middleware.grouper.membership.MembershipType;
60  import edu.internet2.middleware.grouper.misc.CompositeType;
61  import edu.internet2.middleware.grouper.misc.E;
62  import edu.internet2.middleware.grouper.misc.GrouperDAOFactory;
63  import edu.internet2.middleware.grouper.misc.GrouperHasContext;
64  import edu.internet2.middleware.grouper.misc.GrouperVersion;
65  import edu.internet2.middleware.grouper.util.GrouperUtil;
66  import edu.internet2.middleware.grouper.xml.export.XmlExportComposite;
67  import edu.internet2.middleware.grouper.xml.export.XmlImportable;
68  
69  /** 
70   * A composite membership definition within the Groups Registry.
71   * 
72   * A composite group is composed of two groups and a set operator 
73   * (stored in grouper_composites table)
74   * (e.g. union, intersection, etc).  A composite group has no immediate members.
75   * All subjects in a composite group are effective members.
76   * 
77   * <p/>
78   * @author  blair christensen.
79   * @version $Id: Composite.java,v 1.71 2009-12-07 07:31:08 mchyzer Exp $
80   * @since   1.0
81   */
82  @SuppressWarnings("serial")
83  public class Composite extends GrouperAPI implements GrouperHasContext, Hib3GrouperVersioned, XmlImportable<Composite> {
84  
85    /** table for composites */
86    public static final String TABLE_GROUPER_COMPOSITES = "grouper_composites";
87  
88    /** id col in db */
89    public static final String COLUMN_ID = "id";
90  
91    /** uuid col in db */
92    public static final String COLUMN_UUID = "uuid";
93    
94    /** old id col for id conversion */
95    public static final String COLUMN_OLD_ID = "old_id";
96    
97    /** old uuid id col for id conversion */
98    public static final String COLUMN_OLD_UUID = "old_uuid";
99    
100   
101   //*****  START GENERATED WITH GenerateFieldConstants.java *****//
102 
103   /** constant for field name for: createTime */
104   public static final String FIELD_CREATE_TIME = "createTime";
105 
106   /** constant for field name for: creatorUUID */
107   public static final String FIELD_CREATOR_UUID = "creatorUUID";
108 
109   /** constant for field name for: dbVersion */
110   public static final String FIELD_DB_VERSION = "dbVersion";
111 
112   /** constant for field name for: factorOwnerUUID */
113   public static final String FIELD_FACTOR_OWNER_UUID = "factorOwnerUUID";
114 
115   /** constant for field name for: leftFactorUUID */
116   public static final String FIELD_LEFT_FACTOR_UUID = "leftFactorUUID";
117 
118   /** constant for field name for: rightFactorUUID */
119   public static final String FIELD_RIGHT_FACTOR_UUID = "rightFactorUUID";
120 
121   /** constant for field name for: type */
122   public static final String FIELD_TYPE = "type";
123 
124   /** constant for field name for: uuid */
125   public static final String FIELD_UUID = "uuid";
126 
127   /**
128    * fields which are included in db version
129    */
130   private static final Set<String> DB_VERSION_FIELDS = GrouperUtil.toSet(
131       FIELD_CREATE_TIME, FIELD_CREATOR_UUID, FIELD_FACTOR_OWNER_UUID, FIELD_LEFT_FACTOR_UUID, 
132       FIELD_RIGHT_FACTOR_UUID, FIELD_TYPE, FIELD_UUID);
133 
134   /**
135    * fields which are included in clone method
136    */
137   private static final Set<String> CLONE_FIELDS = GrouperUtil.toSet(
138       FIELD_CREATE_TIME, FIELD_CREATOR_UUID, FIELD_DB_VERSION, FIELD_FACTOR_OWNER_UUID, 
139       FIELD_HIBERNATE_VERSION_NUMBER, FIELD_LEFT_FACTOR_UUID, FIELD_RIGHT_FACTOR_UUID, FIELD_TYPE, 
140       FIELD_UUID);
141 
142   //*****  END GENERATED WITH GenerateFieldConstants.java *****//
143 
144   /** */
145   private long    createTime;
146   /** */
147   private String  creatorUUID;
148   /** */
149   private String  factorOwnerUUID;
150   /** */
151   private String  leftFactorUUID;
152   /** */
153   private String  rightFactorUUID;
154   /** */
155   private String  type;
156   /** */
157   private String  uuid;
158 
159   /**
160    * Return this {@link Composite}'s left factor.
161    * <pre class="eg">
162    * try {
163    *   Group left = c.getLeftGroup();
164    * }
165    * catch (GroupNotFoundException eGNF) {
166    *   // unable to retrieve group
167    * }
168    * </pre>
169    * @return  Left factor {@link Group}.
170    * @throws  GroupNotFoundException
171    * @since   1.0
172    */
173   public Group getLeftGroup() 
174     throws  GroupNotFoundException
175   {
176     return this._getGroup( this.getLeftFactorUuid() );
177   } // public Group getLeftGroup()
178 
179   /**
180    * Return this {@link Composite}'s owner.
181    * <pre class="eg">
182    * try {
183    *   Group owner = c.geOwnerGroup();
184    * }
185    * catch (GroupNotFoundException eGNF) {
186    *   // unable to retrieve group
187    * }
188    * </pre>
189    * @return  Owner {@link Group}.
190    * @throws  GroupNotFoundException
191    * @since   1.0
192    */
193   public Group getOwnerGroup() 
194     throws  GroupNotFoundException
195   {
196     return this._getGroup( this.getFactorOwnerUuid() );
197   } // public Group getOwnerGroup()
198 
199   /**
200    * Return this {@link Composite}'s right factor.
201    * <pre class="eg">
202    * try {
203    *   Group right = c.getRightGroup();
204    * }
205    * catch (GroupNotFoundException eGNF) {
206    *   // unable to retrieve group
207    * }
208    * </pre>
209    * @return  Right factor {@link Group}.
210    * @throws  GroupNotFoundException
211    * @since   1.0
212    */
213   public Group getRightGroup() 
214     throws  GroupNotFoundException
215   {
216     return this._getGroup( this.getRightFactorUuid() );
217   } // public Group getLeftGroup()
218 
219   /**
220    * Return this composite's type.
221    * <pre class="eg">
222    * CompositeType type = c.getType();
223    * </pre>
224    * @return  {@link CompositeType} of this {@link Composite}.
225    * @since   1.0
226    */
227   public CompositeType getType() {
228     return CompositeType.valueOfIgnoreCase( this.type );
229   }
230 
231   /**
232    * simple getter for type for db
233    * @return type db
234    */
235   public String getTypeDb() {
236     return this.type;
237   }
238   
239   /**
240    * @return string
241    * @since   1.0
242    */
243   public String toString() {
244     return  new ToStringBuilder(this, ToStringStyle.SIMPLE_STYLE)
245       .append( "type",  this.getType()                               )
246       .append( "owner", Quote.single( this.internal_getOwnerName() ) )
247       .append( "left",  Quote.single( this.internal_getLeftName()  ) )
248       .append( "right", Quote.single( this.internal_getRightName() ) )
249       .toString();
250   } // public String toString()
251 
252 
253   // PROTECTED CLASS METHODS //
254 
255   /** logger */
256   private static final Log LOG = GrouperUtil.getLog(Composite.class);
257 
258 
259 
260   // PROTECTED INSTANCE METHODS //
261 
262   /**
263    * @return name
264    * 
265    */
266   public String getName() {
267     return this.getClass().getName();
268   } 
269 
270   /**
271    * left name
272    * @return left name
273    */
274   public String internal_getLeftName() {
275     return this._getName( this.getLeftFactorUuid(), E.COMP_NULL_LEFT_GROUP );
276   } 
277 
278   /**
279    * owner name
280    * @return the owner name
281    */
282   public String internal_getOwnerName() {
283     return this._getName( this.getFactorOwnerUuid(), E.COMP_NULL_OWNER_GROUP );
284   }
285 
286   /**
287    * right name
288    * @return right name
289    */
290   public String internal_getRightName() {
291     return this._getName( this.getRightFactorUuid(), E.COMP_NULL_RIGHT_GROUP );
292   }
293 
294   /**
295    * used when calling getLeftGroup(), getRightGroup(), or getOwnerGroup()
296    * @param uuid
297    * @return group
298    * @throws GroupNotFoundException
299    */
300   private Group _getGroup(String uuid) 
301     throws  GroupNotFoundException {
302     Group g = GrouperDAOFactory.getFactory().getGroup().findByUuid(uuid, true) ;
303     if (!GrouperSession.staticGrouperSession().getMember().canView(g)) {
304       throw new GroupNotFoundException("Cant view group: " + g.getUuid());
305     }
306     return g;
307   } 
308 
309   /**
310    * 
311    * @param uuid
312    * @param msg
313    * @return name
314    */
315   private String _getName(String uuid, String msg) {
316     try {
317       Group g = GrouperDAOFactory.getFactory().getGroup().findByUuid(uuid, true) ;
318       return g.getName();
319     }
320     catch (GroupNotFoundException eGNF) {
321       //CH 20090308 why does this just not throw the exception?
322       LOG.error( msg + Quote.single( this.getUuid() ) + ": " + eGNF.getMessage() );
323       return GrouperConfig.EMPTY_STRING;
324     }
325   } 
326 
327   /**
328    * @param other 
329    * @return if one equals the other
330    * @since   1.2.0
331    */  
332   public boolean equals(Object other) {
333     if (this == other) {
334       return true;
335     }
336     if (!(other instanceof Composite)) {
337       return false;
338     }
339     Composite/edu/internet2/middleware/grouper/Composite.html#Composite">Composite otherComposite = (Composite) other;
340     return new EqualsBuilder()
341       .append( this.factorOwnerUUID, otherComposite.factorOwnerUUID )
342       .append( this.leftFactorUUID, otherComposite.leftFactorUUID )
343       .append( this.rightFactorUUID, otherComposite.rightFactorUUID )
344       .append( this.type, otherComposite.type )
345       .isEquals();
346   }
347 
348   /**
349    * @return create time
350    * @since   1.2.0
351    */
352   public long getCreateTime() {
353     return this.createTime;
354   }
355 
356   /**
357    * @return creator uuid
358    * @since   1.2.0
359    */
360   public String getCreatorUuid() {
361     return this.creatorUUID;
362   }
363 
364   /**
365    * @return factor owner uuid
366    * @since   1.2.0
367    */
368   public String getFactorOwnerUuid() {
369     return this.factorOwnerUUID;
370   }
371 
372   /**
373    * @return left factor uuid
374    * @since   1.2.0
375    */
376   public String getLeftFactorUuid() {
377     return this.leftFactorUUID;
378   }
379 
380   /**
381    * @return right factor uuid
382    * @since   1.2.0
383    */
384   public String getRightFactorUuid() {
385     return this.rightFactorUUID;
386   }
387 
388   /**
389    * @return uuid
390    * @since   1.2.0
391    */
392   public String getUuid() {
393     return this.uuid;
394   }
395 
396   /**
397    * @return hashcode
398    * @since   1.2.0
399    */
400   public int hashCode() {
401     return new HashCodeBuilder()
402       .append( this.factorOwnerUUID )
403       .append( this.leftFactorUUID )
404       .append( this.rightFactorUUID )
405       .append( this.type )
406       .toHashCode();
407   } // public int hashCode()
408 
409   /**
410    * @param createTime 
411    * @since   1.2.0
412    */
413   public void setCreateTime(long createTime) {
414     this.createTime = createTime;
415   }
416 
417   /**
418    * @param creatorUUID 
419    * @since   1.2.0
420    */
421   public void setCreatorUuid(String creatorUUID) {
422     this.creatorUUID = creatorUUID;
423   }
424 
425   /**
426    * @param factorOwnerUUID 
427    * @since   1.2.0
428    */
429   public void setFactorOwnerUuid(String factorOwnerUUID) {
430     this.factorOwnerUUID = factorOwnerUUID;
431   }
432 
433   /**
434    * @param leftFactorUUID 
435    * @since   1.2.0
436    */
437   public void setLeftFactorUuid(String leftFactorUUID) {
438     this.leftFactorUUID = leftFactorUUID;
439   }
440 
441   /**
442    * @param rightFactorUUID 
443    * @since   1.2.0
444    */
445   public void setRightFactorUuid(String rightFactorUUID) {
446     this.rightFactorUUID = rightFactorUUID;
447   }
448 
449   /**
450    * @param type 
451    * @since   1.2.0
452    */
453   public void setTypeDb(String type) {
454     this.type = type;
455   }
456 
457   /**
458    * @param uuid 
459    * @since   1.2.0
460    */
461   public void setUuid(String uuid) {
462     this.uuid = uuid;
463   }
464 
465   /**
466    * @return string
467    * @since   1.2.0
468    */
469   public String toStringDto() {
470     return new ToStringBuilder(this)
471       .append( "createTime",      this.getCreateTime()        )
472       .append( "creatorUuid",     this.getCreatorUuid()       )
473       .append( "factorUuid",      this.getFactorOwnerUuid()   )
474       .append( "leftFactorUuid",  this.getLeftFactorUuid()    )
475       .append( "ownerUuid",       this.getUuid()              )
476       .append( "rightFactorUuid", this.getRightFactorUuid()   )
477       .append( "type",            this.getType()              )
478       .toString();
479   }
480 
481   /**
482    * @see edu.internet2.middleware.grouper.GrouperAPI#onPostDelete(edu.internet2.middleware.grouper.hibernate.HibernateSession)
483    */
484   @Override
485   public void onPostDelete(HibernateSession hibernateSession) {
486     super.onPostDelete(hibernateSession);
487 
488     // fix composites
489     Set<Composite> composites = GrouperDAOFactory.getFactory().getComposite().findAsFactorOrHasMemberOfFactor(this.getFactorOwnerUuid());
490     Set<String> groupIds = new LinkedHashSet<String>();
491 
492     if (composites.size() > 0) {
493       groupIds = Membership.fixComposites(composites, this.getFactorOwnerUuid(), membersDeletedOnPreDelete);
494     }
495     
496     // update last_membership_change
497     if (membersDeletedOnPreDelete.size() > 0) {
498       groupIds.add(this.getFactorOwnerUuid());
499     }
500     
501     Membership.updateLastMembershipChangeDuringMembersListUpdate(groupIds);
502     
503     membersDeletedOnPreDelete = null;
504     
505     GrouperHooksUtils.schedulePostCommitHooksIfRegistered(GrouperHookType.COMPOSITE, 
506         CompositeHooks.METHOD_COMPOSITE_POST_COMMIT_DELETE, HooksCompositeBean.class, 
507         this, Composite.class);
508     
509     GrouperHooksUtils.callHooksIfRegistered(this, GrouperHookType.COMPOSITE, 
510         CompositeHooks.METHOD_COMPOSITE_POST_DELETE, HooksCompositeBean.class, 
511         this, Composite.class, VetoTypeGrouper.COMPOSITE_POST_DELETE, false, true);
512   }
513 
514   /**
515    * @see edu.internet2.middleware.grouper.GrouperAPI#onPostSave(edu.internet2.middleware.grouper.hibernate.HibernateSession)
516    */
517   @Override
518   public void onPostSave(HibernateSession hibernateSession) {
519     super.onPostSave(hibernateSession);
520     
521     // add the composite memberships
522     Set<String> membersList = new LinkedHashSet<String>();
523     if (this.getType().equals(CompositeType.COMPLEMENT)) {
524       membersList.addAll(this.evaluateAddCompositeMembershipComplement());
525     } else if (this.getType().equals(CompositeType.INTERSECTION)) {
526       membersList.addAll(this.evaluateAddCompositeMembershipIntersection());
527     } else if (this.getType().equals(CompositeType.UNION)) {
528       membersList.addAll(this.evaluateAddCompositeMembershipUnion());
529     } else {
530       throw new IllegalStateException(E.MOF_CTYPE
531           + this.getType().toString());
532     }
533     
534     GrouperDAOFactory.getFactory().getMembership().save(this.createNewCompositeMembershipObjects(membersList));
535     
536     // fix composites
537     Set<Composite> composites = GrouperDAOFactory.getFactory().getComposite().findAsFactorOrHasMemberOfFactor(this.getFactorOwnerUuid());
538     Set<String> groupIds = new LinkedHashSet<String>();
539 
540     if (composites.size() > 0) {
541       groupIds = Membership.fixComposites(composites, this.getFactorOwnerUuid(), membersList);
542     }
543     
544     // update last_membership_change
545     if (membersList.size() > 0) {
546       groupIds.add(this.getFactorOwnerUuid());
547     }
548     
549     Membership.updateLastMembershipChangeDuringMembersListUpdate(groupIds);
550 
551     // update group set object to specify type of composite
552     GroupSet selfGroupSet = 
553       GrouperDAOFactory.getFactory().getGroupSet().findSelfGroup(this.getFactorOwnerUuid(), Group.getDefaultList().getUuid());
554     selfGroupSet.setType(MembershipType.COMPOSITE.getTypeString());
555     GrouperDAOFactory.getFactory().getGroupSet().update(selfGroupSet);
556 
557     GrouperHooksUtils.callHooksIfRegistered(this, GrouperHookType.COMPOSITE, 
558         CompositeHooks.METHOD_COMPOSITE_POST_INSERT, HooksCompositeBean.class, 
559         this, Composite.class, VetoTypeGrouper.COMPOSITE_POST_INSERT, true, false);
560 
561     //do these second so the right object version is set, and dbVersion is ok
562     GrouperHooksUtils.schedulePostCommitHooksIfRegistered(GrouperHookType.COMPOSITE, 
563         CompositeHooks.METHOD_COMPOSITE_POST_COMMIT_INSERT, HooksCompositeBean.class, 
564         this, Composite.class);
565   }
566 
567   /**
568    * @see edu.internet2.middleware.grouper.GrouperAPI#onPostUpdate(edu.internet2.middleware.grouper.hibernate.HibernateSession)
569    */
570   @Override
571   public void onPostUpdate(HibernateSession hibernateSession) {
572     super.onPostUpdate(hibernateSession);
573 
574     GrouperHooksUtils.schedulePostCommitHooksIfRegistered(GrouperHookType.COMPOSITE, 
575         CompositeHooks.METHOD_COMPOSITE_POST_COMMIT_UPDATE, HooksCompositeBean.class, 
576         this, Composite.class);
577     
578     GrouperHooksUtils.callHooksIfRegistered(this, GrouperHookType.COMPOSITE, 
579         CompositeHooks.METHOD_COMPOSITE_POST_UPDATE, HooksCompositeBean.class, 
580         this, Composite.class, VetoTypeGrouper.COMPOSITE_POST_UPDATE, true, false);
581   }
582 
583   /** we're using this to save members deleted during a composite delete onPreDelete so it can be used again onPostDelete */
584   private Set<String> membersDeletedOnPreDelete;
585 
586   
587   /**
588    * @see edu.internet2.middleware.grouper.GrouperAPI#onPreDelete(edu.internet2.middleware.grouper.hibernate.HibernateSession)
589    */
590   @Override
591   public void onPreDelete(HibernateSession hibernateSession) {
592     super.onPreDelete(hibernateSession);
593     
594     // delete the composite memberships
595     Set<Membership> mships = GrouperDAOFactory.getFactory().getMembership().findAllByGroupOwnerAndFieldAndType( 
596         this.getFactorOwnerUuid(), Group.getDefaultList(), "composite", false);
597 
598     membersDeletedOnPreDelete = new LinkedHashSet<String>();
599     Iterator<Membership> iter = mships.iterator();
600     while (iter.hasNext()) {
601       membersDeletedOnPreDelete.add(iter.next().getMemberUuid());
602     }
603     
604     GrouperDAOFactory.getFactory().getMembership().delete(mships);
605     
606     // update the membership type of the group set to 'immediate'
607     GroupSet selfGroupSet = 
608       GrouperDAOFactory.getFactory().getGroupSet().findSelfGroup(this.getFactorOwnerUuid(), Group.getDefaultList().getUuid());
609     selfGroupSet.setType(MembershipType.IMMEDIATE.getTypeString());
610     GrouperDAOFactory.getFactory().getGroupSet().update(selfGroupSet);
611     
612     GrouperHooksUtils.callHooksIfRegistered(this, GrouperHookType.COMPOSITE, 
613         CompositeHooks.METHOD_COMPOSITE_PRE_DELETE, HooksCompositeBean.class, 
614         this, Composite.class, VetoTypeGrouper.COMPOSITE_PRE_DELETE, false, false);
615   
616   }
617 
618   /**
619    * 
620    * @see edu.internet2.middleware.grouper.GrouperAPI#onPreSave(edu.internet2.middleware.grouper.hibernate.HibernateSession)
621    */
622   @Override
623   public void onPreSave(HibernateSession hibernateSession) {
624     super.onPreSave(hibernateSession);
625     
626     GrouperHooksUtils.callHooksIfRegistered(this, GrouperHookType.COMPOSITE, 
627         CompositeHooks.METHOD_COMPOSITE_PRE_INSERT, HooksCompositeBean.class, 
628         this, Composite.class, VetoTypeGrouper.COMPOSITE_PRE_INSERT, false, false);
629   
630   }
631 
632   /**
633    * @see edu.internet2.middleware.grouper.GrouperAPI#onPreUpdate(edu.internet2.middleware.grouper.hibernate.HibernateSession)
634    */
635   @Override
636   public void onPreUpdate(HibernateSession hibernateSession) {
637     super.onPreUpdate(hibernateSession);
638     
639     GrouperHooksUtils.callHooksIfRegistered(this, GrouperHookType.COMPOSITE, 
640         CompositeHooks.METHOD_COMPOSITE_PRE_UPDATE, HooksCompositeBean.class, 
641         this, Composite.class, VetoTypeGrouper.COMPOSITE_PRE_UPDATE, false, false);
642   }
643 
644   /**
645    * save the state when retrieving from DB
646    * @return the dbVersion
647    */
648   @Override
649   public Composite dbVersion() {
650     return (Composite)this.dbVersion;
651   }
652 
653   /**
654    * note, these are massaged so that name, extension, etc look like normal fields.
655    * access with fieldValue()
656    * @see edu.internet2.middleware.grouper.GrouperAPI#dbVersionDifferentFields()
657    */
658   @Override
659   public Set<String> dbVersionDifferentFields() {
660     if (this.dbVersion == null) {
661       throw new RuntimeException("State was never stored from db");
662     }
663     //easier to unit test if everything is ordered
664     Set<String> result = GrouperUtil.compareObjectFields(this, this.dbVersion,
665         DB_VERSION_FIELDS, null);
666     return result;
667   }
668 
669   /**
670    * take a snapshot of the data since this is what is in the db
671    */
672   @Override
673   public void dbVersionReset() {
674     //lets get the state from the db so we know what has changed
675     this.dbVersion = GrouperUtil.clone(this, DB_VERSION_FIELDS);
676   }
677 
678   /**
679    * deep clone the fields in this object
680    */
681   @Override
682   public Composite clone() {
683     return GrouperUtil.clone(this, CLONE_FIELDS);
684   }
685 
686   /** context id of the transaction */
687   private String contextId;
688 
689   /**
690    * context id of the transaction
691    * @return context id
692    */
693   public String getContextId() {
694     return this.contextId;
695   }
696 
697   /**
698    * context id of the transaction
699    * @param contextId1
700    */
701   public void setContextId(String contextId1) {
702     this.contextId = contextId1;
703   }
704   
705 
706 
707   /**
708    * @return the set of members
709    */
710   private Set<String> evaluateAddCompositeMembershipComplement() {
711 
712     Set<String> memberUUIDs = GrouperDAOFactory.getFactory().getMember()
713       ._internal_membersComplement(this.getLeftFactorUuid(),
714           this.getRightFactorUuid());
715 
716     return memberUUIDs;
717   } 
718 
719   /**
720    * @return the set of members
721    */
722   private Set<String> evaluateAddCompositeMembershipIntersection() {
723     
724     Set<String> memberUUIDs = GrouperDAOFactory.getFactory().getMember()
725       ._internal_membersIntersection(this.getLeftFactorUuid(),
726         this.getRightFactorUuid());
727 
728     return memberUUIDs;
729   }
730 
731   /**
732    * @return the set of members
733    */
734   private Set<String> evaluateAddCompositeMembershipUnion() {
735     
736     Set<String> memberUUIDs = GrouperDAOFactory.getFactory().getMember()
737       ._internal_membersUnion(this.getLeftFactorUuid(),
738       this.getRightFactorUuid());
739 
740     return memberUUIDs;
741   }
742   
743   /**
744    * @param memberUUIDs
745    * @return set
746    */
747   private Set<Membership> createNewCompositeMembershipObjects(Set<String> memberUUIDs) {
748     Set<Membership> mships = new LinkedHashSet<Membership>();
749     Iterator<String> it = memberUUIDs.iterator();
750     while (it.hasNext()) {
751       Membership ms = internal_createNewCompositeMembershipObject(this.getFactorOwnerUuid(), it.next(), this.getUuid());
752       mships.add(ms);
753     }
754     return mships;
755   }
756 
757 
758   /**
759    * 
760    * @param ownerGroupId
761    * @param memberUuid
762    * @param viaCompositeId
763    * @return membership
764    */
765   public static Membership internal_createNewCompositeMembershipObject(String ownerGroupId, String memberUuid, String viaCompositeId) {
766     Membershipuper/Membership.html#Membership">Membership ms = new Membership();
767     ms.setCreatorUuid(GrouperSession.staticGrouperSession().getMember().getUuid());
768     ms.setDepth(0);
769     ms.setFieldId(Group.getDefaultList().getUuid());
770     ms.setMemberUuid(memberUuid);
771     ms.setOwnerGroupId(ownerGroupId);
772     ms.setType(MembershipType.COMPOSITE.getTypeString());
773     ms.setViaCompositeId(viaCompositeId);
774 
775     return ms;
776   }
777 
778   /**
779    * @see edu.internet2.middleware.grouper.xml.export.XmlImportable#xmlCopyBusinessPropertiesToExisting(java.lang.Object)
780    */
781   public void xmlCopyBusinessPropertiesToExisting(Composite existingRecord) {
782     existingRecord.setFactorOwnerUuid(this.factorOwnerUUID);
783     existingRecord.setLeftFactorUuid(this.leftFactorUUID);
784     existingRecord.setRightFactorUuid(this.rightFactorUUID);
785     existingRecord.setTypeDb(this.type);
786     existingRecord.setUuid(this.getUuid());
787   }
788 
789   /**
790    * @see edu.internet2.middleware.grouper.xml.export.XmlImportable#xmlDifferentBusinessProperties(java.lang.Object)
791    */
792   public boolean xmlDifferentBusinessProperties(Composite other) {
793     if (!StringUtils.equals(this.factorOwnerUUID, other.factorOwnerUUID)) {
794       return true;
795     }
796     if (!StringUtils.equals(this.leftFactorUUID, other.leftFactorUUID)) {
797       return true;
798     }
799     if (!StringUtils.equals(this.rightFactorUUID, other.rightFactorUUID)) {
800       return true;
801     }
802     if (!StringUtils.equals(this.type, other.type)) {
803       return true;
804     }
805     if (!StringUtils.equals(this.uuid, other.uuid)) {
806       return true;
807     }
808     return false;
809   }
810 
811   /**
812    * @see edu.internet2.middleware.grouper.xml.export.XmlImportable#xmlDifferentUpdateProperties(java.lang.Object)
813    */
814   public boolean xmlDifferentUpdateProperties(Composite other) {
815     if (!StringUtils.equals(this.contextId, other.contextId)) {
816       return true;
817     }
818     if (this.createTime != other.createTime) {
819       return true;
820     }
821     if (!StringUtils.equals(this.creatorUUID, other.creatorUUID)) {
822       return true;
823     }
824     if (!GrouperUtil.equals(this.getHibernateVersionNumber(), other.getHibernateVersionNumber())) {
825       return true;
826     }
827     return false;
828   }
829 
830   /**
831    * @see edu.internet2.middleware.grouper.xml.export.XmlImportable#xmlRetrieveByIdOrKey()
832    */
833   public Composite xmlRetrieveByIdOrKey() {
834     return GrouperDAOFactory.getFactory().getComposite().findByUuidOrName(this.uuid, this.factorOwnerUUID, this.leftFactorUUID, this.rightFactorUUID, this.type, false,
835         new QueryOptions().secondLevelCache(false));
836   }
837 
838   /**
839    * @see edu.internet2.middleware.grouper.xml.export.XmlImportable#xmlSaveBusinessProperties(java.lang.Object)
840    */
841   public Compositeernet2/middleware/grouper/Composite.html#Composite">Composite xmlSaveBusinessProperties(Composite existingRecord) {
842     //if its an insert, call the business method
843     if (existingRecord == null) {
844       Group owner = GroupFinder.findByUuid(GrouperSession.staticGrouperSession(), this.factorOwnerUUID, true);
845       Group left = GroupFinder.findByUuid(GrouperSession.staticGrouperSession(), this.leftFactorUUID, true);
846       Group right = GroupFinder.findByUuid(GrouperSession.staticGrouperSession(), this.rightFactorUUID, true);
847       existingRecord = owner.internal_addCompositeMember(GrouperSession.staticGrouperSession(), this.getType(), left, right, this.uuid);
848     }
849     this.xmlCopyBusinessPropertiesToExisting(existingRecord);
850     //if its an insert or update, then do the rest of the fields
851     existingRecord.store();
852     return existingRecord;
853 
854   }
855 
856   /**
857    * store this object to the DB.
858    */
859   public void store() {    
860     GrouperDAOFactory.getFactory().getComposite().update(this);
861   }
862   /**
863    * @see edu.internet2.middleware.grouper.xml.export.XmlImportable#xmlSaveUpdateProperties()
864    */
865   public void xmlSaveUpdateProperties() {
866     GrouperDAOFactory.getFactory().getComposite().saveUpdateProperties(this);
867   }
868 
869   /**
870    * convert to xml bean for export
871    * @param grouperVersion
872    * @return xml bean
873    */
874   public XmlExportComposite xmlToExportComposite(GrouperVersion grouperVersion) {
875     
876     if (grouperVersion == null) {
877       throw new RuntimeException();
878     }
879     
880     XmlExportCompositetComposite.html#XmlExportComposite">XmlExportComposite xmlExportComposite = new XmlExportComposite();
881     
882     xmlExportComposite.setContextId(this.getContextId());
883     xmlExportComposite.setCreateTime(GrouperUtil.dateStringValue(new Date(this.getCreateTime())));
884     xmlExportComposite.setCreatorId(this.getCreatorUuid());
885     xmlExportComposite.setHibernateVersionNumber(this.getHibernateVersionNumber());
886     xmlExportComposite.setLeftFactor(this.getLeftFactorUuid());
887     xmlExportComposite.setOwner(this.getFactorOwnerUuid());
888     xmlExportComposite.setRightFactor(this.getRightFactorUuid());
889     xmlExportComposite.setType(this.getTypeDb());
890     xmlExportComposite.setUuid(this.getUuid());
891     
892     return xmlExportComposite;
893   }
894   /**
895    * @see edu.internet2.middleware.grouper.xml.export.XmlImportable#xmlGetId()
896    */
897   public String xmlGetId() {
898     return this.getUuid();
899   }
900 
901   /**
902    * @see edu.internet2.middleware.grouper.xml.export.XmlImportable#xmlSetId(java.lang.String)
903    */
904   public void xmlSetId(String theId) {
905     this.setUuid(theId);
906   }
907   
908   /**
909    * @see edu.internet2.middleware.grouper.xml.export.XmlImportableBase#xmlToString()
910    */
911   public String xmlToString() {
912     StringWriter stringWriter = new StringWriter();
913     
914     stringWriter.write("Composite: " + this.getUuid() + ", ");
915 
916 //    XmlExportUtils.toStringComposite(stringWriter, this, false);
917     
918     return stringWriter.toString();
919     
920   }
921 
922 } 
923