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.Serializable;
35  import java.util.LinkedHashSet;
36  import java.util.Set;
37  
38  import org.apache.commons.lang.StringUtils;
39  import org.apache.commons.lang.builder.EqualsBuilder;
40  import org.apache.commons.lang.builder.HashCodeBuilder;
41  import org.apache.commons.lang.builder.ToStringBuilder;
42  import org.apache.commons.lang.time.StopWatch;
43  import org.apache.commons.logging.Log;
44  
45  import edu.internet2.middleware.grouper.annotations.GrouperIgnoreClone;
46  import edu.internet2.middleware.grouper.annotations.GrouperIgnoreFieldConstant;
47  import edu.internet2.middleware.grouper.attr.AttributeDef;
48  import edu.internet2.middleware.grouper.attr.AttributeDefName;
49  import edu.internet2.middleware.grouper.attr.AttributeDefScopeType;
50  import edu.internet2.middleware.grouper.attr.AttributeDefType;
51  import edu.internet2.middleware.grouper.attr.AttributeDefValueType;
52  import edu.internet2.middleware.grouper.attr.finder.AttributeDefFinder;
53  import edu.internet2.middleware.grouper.attr.finder.AttributeDefNameFinder;
54  import edu.internet2.middleware.grouper.attr.value.AttributeAssignValue;
55  import edu.internet2.middleware.grouper.audit.AuditEntry;
56  import edu.internet2.middleware.grouper.audit.AuditTypeBuiltin;
57  import edu.internet2.middleware.grouper.cache.GrouperCache;
58  import edu.internet2.middleware.grouper.cfg.GrouperConfig;
59  import edu.internet2.middleware.grouper.exception.InsufficientPrivilegeException;
60  import edu.internet2.middleware.grouper.exception.SchemaException;
61  import edu.internet2.middleware.grouper.hibernate.AuditControl;
62  import edu.internet2.middleware.grouper.hibernate.GrouperTransactionType;
63  import edu.internet2.middleware.grouper.hibernate.HibernateHandler;
64  import edu.internet2.middleware.grouper.hibernate.HibernateHandlerBean;
65  import edu.internet2.middleware.grouper.hibernate.HibernateSession;
66  import edu.internet2.middleware.grouper.internal.dao.GrouperDAOException;
67  import edu.internet2.middleware.grouper.internal.dao.hib3.Hib3AttributeDefNameDAO;
68  import edu.internet2.middleware.grouper.internal.util.GrouperUuid;
69  import edu.internet2.middleware.grouper.internal.util.Quote;
70  import edu.internet2.middleware.grouper.log.EventLog;
71  import edu.internet2.middleware.grouper.misc.E;
72  import edu.internet2.middleware.grouper.misc.GrouperDAOFactory;
73  import edu.internet2.middleware.grouper.misc.M;
74  import edu.internet2.middleware.grouper.privs.Privilege;
75  import edu.internet2.middleware.grouper.privs.PrivilegeHelper;
76  import edu.internet2.middleware.grouper.util.GrouperUtil;
77  import edu.internet2.middleware.grouper.validator.DeleteFieldFromGroupTypeValidator;
78  import edu.internet2.middleware.grouper.validator.ModifyGroupTypeValidator;
79  
80  /** 
81   * Schema specification for a Group type.
82   * <p/>
83   * @author  blair christensen.
84   * @version $Id: GroupType.java,v 1.89 2009-06-10 05:31:35 mchyzer Exp $
85   */
86  public class GroupType extends GrouperAPI implements Serializable, Comparable {
87    
88    /** name of table for grouper_types */
89    public static final String TABLE_OLD_GROUPER_TYPES = "grouper_types";
90    
91    /** uuid col in db */
92    public static final String COLUMN_TYPE_UUID = "type_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_TYPE_UUID = "old_type_uuid";
99   
100   //*****  START GENERATED WITH GenerateFieldConstants.java *****//
101 
102   /** constant for field name for: createTime */
103   public static final String FIELD_CREATE_TIME = "createTime";
104 
105   /** constant for field name for: name */
106   public static final String FIELD_NAME = "name";
107 
108   /** constant for field name for: uuid */
109   public static final String FIELD_UUID = "uuid";
110 
111   /**
112    * fields which are included in clone method
113    */
114   private static final Set<String> CLONE_FIELDS = GrouperUtil.toSet(
115       FIELD_CREATE_TIME, FIELD_DB_VERSION, FIELD_HIBERNATE_VERSION_NUMBER, 
116       FIELD_NAME, FIELD_UUID);
117 
118   //*****  END GENERATED WITH GenerateFieldConstants.java *****//
119 
120   /** */
121   public static final long serialVersionUID = 8214760621248803096L;
122 
123   /**
124    * Create a new {@link GroupType}.  
125    * <p/>
126    * Create a new custom group type that can be assigned to existing or
127    * new groups.  If the type already exists, a {@link SchemaException}
128    * will be thrown.  If the subject is not root-like, an 
129    * {@link InsufficientPrivilegeException} will be thrown.
130    * <pre class="eg">
131    * try {
132    *   GroupType type = GroupType.createType(s, "my custom type");
133    * }
134    * catch (InsufficientPrivilegeException eIP) {
135    *   // Subject not privileged to add group types.
136    * }
137    * catch (SchemaException eS) {
138    *   // Type not created
139    * }
140    * </pre>
141    * @param   s     Create type within this session context.
142    * @param   name  Create type with this name.
143    * @return  New {@link GroupType}.
144    * @throws  InsufficientPrivilegeException
145    * @throws  SchemaException
146    * @deprecated
147    */
148   public static GroupType createType(GrouperSession s, String name) 
149     throws  InsufficientPrivilegeException, SchemaException  {
150     return createTypeHelper(s, name, true, null);
151   }
152 
153   /**
154    * Create a new {@link GroupType}.  
155    * <p/>
156    * Create a new custom group type that can be assigned to existing or
157    * new groups.  If the type already exists, a {@link SchemaException}
158    * will be thrown.  If the subject is not root-like, an 
159    * {@link InsufficientPrivilegeException} will be thrown.
160    * <pre class="eg">
161    * try {
162    *   GroupType type = GroupType.createType(s, "my custom type");
163    * }
164    * catch (InsufficientPrivilegeException eIP) {
165    *   // Subject not privileged to add group types.
166    * }
167    * catch (SchemaException eS) {
168    *   // Type not created
169    * }
170    * </pre>
171    * @param   s     Create type within this session context.
172    * @param   name  Create type with this name.
173    * @param exceptionIfExists 
174    * @return  New {@link GroupType}.
175    * @throws  InsufficientPrivilegeException
176    * @throws SchemaException 
177    * @deprecated
178    */
179   public static GroupType createType(GrouperSession s, String name, 
180       boolean exceptionIfExists) 
181     throws  InsufficientPrivilegeException, SchemaException  {
182     return createTypeHelper(s, name, exceptionIfExists, null);
183   }
184 
185   /**
186    * Create a new {@link GroupType}.  
187    * <p/>
188    * Create a new custom group type that can be assigned to existing or
189    * new groups.  If the type already exists, a {@link SchemaException}
190    * will be thrown.  If the subject is not root-like, an 
191    * {@link InsufficientPrivilegeException} will be thrown.
192    * <pre class="eg">
193    * try {
194    *   GroupType type = GroupType.createType(s, "my custom type");
195    * }
196    * catch (InsufficientPrivilegeException eIP) {
197    *   // Subject not privileged to add group types.
198    * }
199    * catch (SchemaException eS) {
200    *   // Type not created
201    * }
202    * </pre>
203    * @param   s     Create type within this session context.
204    * @param   name  Create type with this name.
205    * @param exceptionIfExists 
206    * @param uuid 
207    * @return  New {@link GroupType}.
208    * @throws  InsufficientPrivilegeException
209    * @throws SchemaException 
210    * @deprecated
211    */
212   public static GroupType createType(GrouperSession s, String name, 
213       boolean exceptionIfExists, String uuid) 
214     throws  InsufficientPrivilegeException, SchemaException  {
215     return createTypeHelper(s, name, exceptionIfExists, uuid);
216   }
217 
218   /**
219    * @param s
220    * @param name
221    * @param exceptionIfExists 
222    * @param uuid 
223    * @return the type
224    * @throws InsufficientPrivilegeException
225    * @throws SchemaException
226    * @deprecated
227    */
228   private static GroupType createTypeHelper(GrouperSession s, String name, boolean exceptionIfExists, String uuid)
229       throws InsufficientPrivilegeException, SchemaException {
230     //note, no need for GrouperSession inverse of control
231     StopWatch sw = new StopWatch();
232     sw.start();
233     boolean[] existedAlready = new boolean[1];
234     GroupType type = internal_createType(s, name, exceptionIfExists, existedAlready, StringUtils.trimToNull(uuid));
235     sw.stop();
236     if (!existedAlready[0]) {
237       EventLog.info(s, M.GROUPTYPE_ADD + Quote.single( type.getName() ), sw);
238     }
239     return type;
240   }
241 
242   /** */
243   private long    createTime;
244   
245   /** */
246   @GrouperIgnoreFieldConstant
247   @GrouperIgnoreClone
248   private Set     fields;
249   
250   /** */
251   private String  name;
252   /** */
253   private String  uuid; 
254 
255   /** context id of the transaction */
256   private String contextId;
257   
258   /**
259    * cache of group type id to attribute def name
260    */
261   private static GrouperCache<String, AttributeDefName> attributeDefNameFromTypeIdCache = null;
262   
263   /**
264    * cache of group type id to attribute def name
265    * @return cache
266    */
267   private static GrouperCache<String, AttributeDefName> attributeDefNameFromTypeIdCache() {
268     if (attributeDefNameFromTypeIdCache == null) {
269       synchronized(GroupType.class) {
270         if (attributeDefNameFromTypeIdCache == null) {
271           attributeDefNameFromTypeIdCache = new GrouperCache<String, AttributeDefName>(
272               GroupType.class.getName() + ".attributeDefNameFromTypeIdCache", 200, false, 
273               30, 30, false);
274         }
275       }
276     }
277     return attributeDefNameFromTypeIdCache;
278   }  
279 
280   /**
281    * cache of group type id to legacy attributes
282    */
283   private static GrouperCache<String, Set<AttributeDefName>> legacyAttributesFromTypeIdCache = null;
284   
285   /**
286    * cache of group type id to legacy attributes
287    * @return cache
288    */
289   private static GrouperCache<String, Set<AttributeDefName>> legacyAttributesFromTypeIdCache() {
290     if (legacyAttributesFromTypeIdCache == null) {
291       synchronized(GroupType.class) {
292         if (legacyAttributesFromTypeIdCache == null) {
293           legacyAttributesFromTypeIdCache = new GrouperCache<String, Set<AttributeDefName>>(
294               GroupType.class.getName() + ".legacyAttributesFromTypeIdCache", 200, false, 
295               30, 30, false);
296         }
297       }
298     }
299     return legacyAttributesFromTypeIdCache;
300   }  
301 
302   
303   
304   
305   /**
306    * context id of the transaction
307    * @return context id
308    */
309   public String getContextId() {
310     return this.contextId;
311   }
312 
313   /**
314    * context id of the transaction
315    * @param contextId1
316    */
317   public void setContextId(String contextId1) {
318     this.contextId = contextId1;
319   }
320 
321   /**
322    * Add a custom attribute {@link Field} to a custom {@link GroupType}.
323    * try {
324    *   Field myAttr = type.addAttribute(
325    *     "my attribute", AccessPrivilege.VIEW, AccessPrivilege.UPDATE, false
326    *   );
327    * }
328    * catch (InsufficientPrivilegeException eIP) {
329    *   // Not privileged to add attribute
330    * }
331    * catch (SchemaException eS) {
332    *   // Invalid schema
333    * }
334    * </pre>
335    * @param   s         Add attribute within this session context.
336    * @param   name      Name of attribute.
337    * @return  field
338    * @throws  InsufficientPrivilegeException
339    * @throws  SchemaException
340    * @deprecated
341    */
342   public AttributeDefName addAttribute(
343     GrouperSession s, String name
344   )
345     throws  InsufficientPrivilegeException,
346             SchemaException {
347     return addAttribute(s, name, true);
348   }
349 
350   /**
351    * Add a custom attribute {@link Field} to a custom {@link GroupType}.
352    * try {
353    *   Field myAttr = type.addAttribute(
354    *     "my attribute", AccessPrivilege.VIEW, AccessPrivilege.UPDATE, false
355    *   );
356    * }
357    * catch (InsufficientPrivilegeException eIP) {
358    *   // Not privileged to add attribute
359    * }
360    * catch (SchemaException eS) {
361    *   // Invalid schema
362    * }
363    * </pre>
364    * @param   s         Add attribute within this session context.
365    * @param   name      Name of attribute.
366    * @param exceptionIfExists 
367    * @return  field
368    * @throws  InsufficientPrivilegeException
369    * @throws  SchemaException
370    * @deprecated
371    */
372   public AttributeDefName addAttribute(
373     final GrouperSession s, final String name, final boolean exceptionIfExists
374   )
375     throws  InsufficientPrivilegeException,
376             SchemaException {
377     return addAttribute(s, name, exceptionIfExists, null);
378   }
379 
380   /**
381    * Add a custom attribute {@link Field} to a custom {@link GroupType}.
382    * try {
383    *   Field myAttr = type.addAttribute(
384    *     "my attribute", AccessPrivilege.VIEW, AccessPrivilege.UPDATE, false
385    *   );
386    * }
387    * catch (InsufficientPrivilegeException eIP) {
388    *   // Not privileged to add attribute
389    * }
390    * catch (SchemaException eS) {
391    *   // Invalid schema
392    * }
393    * </pre>
394    * @param   s         Add attribute within this session context.
395    * @param   name      Name of attribute.
396    * @param exceptionIfExists 
397    * @param uuid 
398    * @return  field
399    * @throws  InsufficientPrivilegeException
400    * @throws  SchemaException
401    * @deprecated
402    */
403   public AttributeDefName addAttribute(
404     final GrouperSession s, final String name, final boolean exceptionIfExists, final String uuid
405   )
406     throws  InsufficientPrivilegeException,
407             SchemaException {
408 
409     return (AttributeDefName)HibernateSession.callbackHibernateSession(
410         GrouperTransactionType.READ_WRITE_OR_USE_EXISTING, AuditControl.WILL_NOT_AUDIT, new HibernateHandler() {
411 
412       public Object callback(HibernateHandlerBean hibernateHandlerBean)
413           throws GrouperDAOException {
414 
415         if (!PrivilegeHelper.isRoot(s)) {
416           String msg = "Cannot add legacy attributes.";
417           LOG.error(msg);
418           throw new InsufficientPrivilegeException(msg);
419         }
420         
421         //these are reserved words:
422         if (Group.INTERNAL_FIELD_ATTRIBUTES.contains(name)) {
423           throw new RuntimeException("You cannot add a field which is a reserved word '" 
424               + name + "', reserved words are : " + GrouperUtil.toStringForLog(Group.INTERNAL_FIELD_ATTRIBUTES));
425         }
426       
427         // see if the attribute def exists first.
428         String stemName = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.baseStem");
429         Stem stem = GrouperDAOFactory.getFactory().getStem().findByName(stemName, true);
430         String attributeDefPrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.attributeDef.prefix");
431         String attributePrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.attribute.prefix");
432         AttributeDef attributeDef = AttributeDefFinder.findByName(stemName + ":" + attributeDefPrefix + GroupType.this.name, false);
433         if (attributeDef == null) {
434           // get the attribute definition used for the group type
435           String groupTypePrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.groupType.prefix");
436           AttributeDefName groupType = AttributeDefNameFinder.findByName(stemName + ":" + groupTypePrefix + GroupType.this.name, true);
437           
438           // create it..
439           attributeDef = stem.addChildAttributeDef(attributeDefPrefix + GroupType.this.name, AttributeDefType.attr);
440           attributeDef.setAssignToGroupAssn(true);
441           attributeDef.setValueType(AttributeDefValueType.string);
442           attributeDef.store();
443           
444           // add scope
445           attributeDef.getAttributeDefScopeDelegate().assignScope(AttributeDefScopeType.idEquals, groupType.getId(), null);
446         } else {
447           // see if the attribute already exists.
448           AttributeDefName attribute = AttributeDefNameFinder.findByName(stemName + ":" + attributePrefix + name, false);
449           if (attribute != null) {
450             if (exceptionIfExists) {
451               throw new SchemaException(name + " already exists.");
452             }
453             
454             return attribute;
455           }
456         }
457         
458         return stem.addChildAttributeDefName(attributeDef, attributePrefix + name, attributePrefix + name, uuid);
459       }    
460     });          
461   }
462       
463       
464 
465   /**
466    * Add a custom list {@link Field} to a custom {@link GroupType}.
467    * try {
468    *   Field myList = type.addList(
469    *     s, "my list", AccessPrivilege.VIEW, AccessPrivilege.UPDATE
470    *   );
471    * }
472    * catch (InsufficientPrivilegeException eIP) {
473    *   // Not privileged to add list
474    * }
475    * catch (SchemaException eS) {
476    *   // Invalid schema
477    * }
478    * </pre>
479    * @param   s         Add list within this session context.
480    * @param   name      Name of list.
481    * @param   read      {@link Privilege} required to write to this {@link Field}.
482    * @param   write     {@link Privilege} required to write to this {@link Field}.
483    * @return field
484    * @throws  InsufficientPrivilegeException
485    * @throws  SchemaException
486    * @deprecated
487    */
488   public Field addList(
489     final GrouperSession s, final String name, final Privilegeer/privs/Privilege.html#Privilege">Privilege read, final Privilege write
490   )
491     throws  InsufficientPrivilegeException,
492             SchemaException {
493     return internal_addList(s, name, read, write, null, true);
494   }
495   
496   /**
497    * @param s
498    * @param name
499    * @param read
500    * @param write
501    * @param fieldId
502    * @param exceptionIfExists
503    * @return field
504    * @throws InsufficientPrivilegeException
505    * @throws SchemaException
506    */
507   public Field internal_addList(
508     final GrouperSession s, final String name, final Privilegeer/privs/Privilege.html#Privilege">Privilege read, final Privilege write,
509     final String fieldId, final boolean exceptionIfExists
510   )
511     throws  InsufficientPrivilegeException,
512             SchemaException
513   {
514     final String UUID = StringUtils.isBlank(fieldId) ? GrouperUuid.getUuid() : fieldId;
515 
516     return (Field)HibernateSession.callbackHibernateSession(
517         GrouperTransactionType.READ_WRITE_OR_USE_EXISTING, AuditControl.WILL_NOT_AUDIT, new HibernateHandler() {
518 
519       public Object callback(HibernateHandlerBean hibernateHandlerBean)
520           throws GrouperDAOException {
521       
522           if (!Privilege.isAccess(read)) {
523             throw new SchemaException(E.FIELD_READ_PRIV_NOT_ACCESS + read);
524           }
525           if (!Privilege.isAccess(write)) {
526             throw new SchemaException(E.FIELD_WRITE_PRIV_NOT_ACCESS + write);
527           }
528         
529           if (!PrivilegeHelper.isRoot(s)) {
530             String msg = "Cannot add lists.";
531             LOG.error(msg);
532             throw new InsufficientPrivilegeException(msg);
533           }
534                     
535           // see if the attribute def and attribute exist first.
536           String stemName = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.baseStem");
537           Stem stem = GrouperDAOFactory.getFactory().getStem().findByName(stemName, true);
538           String customListDefPrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.customListDef.prefix");
539           String customListPrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.customList.prefix");
540           
541           // get the attribute definition used for the group type
542           String groupTypeDefPrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.groupTypeDef.prefix");
543           AttributeDef groupTypeDef = AttributeDefFinder.findByName(stemName + ":" + groupTypeDefPrefix + GroupType.this.name, true);
544           
545           AttributeDef customListDef = AttributeDefFinder.findByName(stemName + ":" + customListDefPrefix + GroupType.this.name, false);
546           AttributeDefName customList = AttributeDefNameFinder.findByName(stemName + ":" + customListPrefix + GroupType.this.name, false);
547           if (customListDef == null) {
548             // create it..
549             customListDef = stem.addChildAttributeDef(customListDefPrefix + GroupType.this.name, AttributeDefType.attr);
550             customListDef.setAssignToAttributeDef(true);
551             customListDef.setValueType(AttributeDefValueType.string);
552             customListDef.setMultiValued(true);
553             customListDef.store();
554             
555             // add scope
556             customListDef.getAttributeDefScopeDelegate().assignScope(AttributeDefScopeType.idEquals, groupTypeDef.getId(), null);
557           }
558           
559           if (customList == null) {
560             customList = stem.addChildAttributeDefName(customListDef, customListPrefix + GroupType.this.name, customListPrefix + GroupType.this.name);
561           }
562           
563           AttributeAssignValue attributeAssignValue = groupTypeDef.getAttributeValueDelegate().findValue(customList.getName(), UUID);
564           
565           if (attributeAssignValue == null) {
566             groupTypeDef.getAttributeValueDelegate().addValue(customList.getName(), UUID);
567           } else {
568             if (exceptionIfExists) {
569               throw new RuntimeException(attributeAssignValue.toString() + " already exists.");
570             }
571           }
572           
573           FieldFinder.clearCache();
574           GroupTypeFinder.clearCache();
575           
576           Field field = Field.internal_addField(s, name, FieldType.LIST, read, write, exceptionIfExists, false, null, UUID);
577           
578           Set fields = GroupType.this.getFields();
579           fields.add(field);
580           
581           return field;
582       }
583     });
584   }
585 
586   /**
587    * Delete a custom {@link GroupType} definition.
588    * <p/>
589    * <pre class="eg">
590    * try {
591    *   aGroupType.delete(s);
592    * }
593    * catch (InsufficientPrivilegeException eIP) {
594    *   // Subject not privileged to delete group type.
595    * }
596    * catch (SchemaException eS) {
597    *   // Type could not be deleted
598    * }
599    * </pre>
600    * @param   s     Delete type within this session context.
601    * @throws  InsufficientPrivilegeException
602    * @throws  SchemaException
603    * @since   1.0
604    * @deprecated
605    */
606   public void delete(final GrouperSession s) 
607     throws  InsufficientPrivilegeException,
608             SchemaException {
609     
610     HibernateSession.callbackHibernateSession(
611         GrouperTransactionType.READ_WRITE_OR_USE_EXISTING, AuditControl.WILL_AUDIT, new HibernateHandler() {
612 
613       public Object callback(HibernateHandlerBean hibernateHandlerBean)
614           throws GrouperDAOException {
615         
616         //note, no need for GrouperSession inverse of control
617         StopWatch sw = new StopWatch();
618         sw.start();
619         if (!PrivilegeHelper.isRoot(s)) {
620           String msg = E.GROUPTYPE_NODEL;
621           LOG.error( msg);
622           throw new InsufficientPrivilegeException(msg);
623         }
624         try {
625           Set<Field> fields = GroupType.this.getFields();
626           
627           // verify fields aren't in use
628           for (Field field : fields) {
629             if (GrouperDAOFactory.getFactory().getField().isInUse(field)) {
630               String msg = E.GROUPTYPE_DELINUSE;
631               LOG.error(msg);
632               throw new SchemaException(msg);
633             }
634           }
635           
636           // verify attributes aren't in use
637           String stemName = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.baseStem");
638           String groupTypePrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.groupType.prefix");          
639           AttributeDefName groupType = AttributeDefNameFinder.findByName(stemName + ":" + groupTypePrefix + GroupType.this.name, false);
640           if (groupType != null) {
641             if (GrouperDAOFactory.getFactory().getAttributeAssign().findByAttributeDefNameId(groupType.getId()).size() > 0) {
642               String msg = E.GROUPTYPE_DELINUSE;
643               LOG.error(msg);
644               throw new SchemaException(msg);
645             }
646           }
647           
648           String typeName = GroupType.this.getName(); // For logging purposes
649           
650           if (LOG.isDebugEnabled()) {
651             LOG.debug("Deleting type: " + GroupType.this.getName() + " and fields: " 
652               + Field.fieldNames(fields));
653           }
654           
655           // Now delete
656           GrouperDAOFactory.getFactory().getField().delete(fields);
657           String attributeDefPrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.attributeDef.prefix");
658           String groupTypeDefPrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.groupTypeDef.prefix");          
659           String customListDefPrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.customListDef.prefix");          
660           AttributeDef attributeDef = AttributeDefFinder.findByName(stemName + ":" + attributeDefPrefix + GroupType.this.name, false);
661           AttributeDef groupTypeDef = AttributeDefFinder.findByName(stemName + ":" + groupTypeDefPrefix + GroupType.this.name, false);
662           AttributeDef customListDefDef = AttributeDefFinder.findByName(stemName + ":" + customListDefPrefix + GroupType.this.name, false);
663 
664           if (groupType != null) {
665             groupType.delete();
666             GroupType.this.setContextId(groupType.getContextId());
667           }
668           
669           if (attributeDef != null) {
670             attributeDef.delete();
671           }
672           if (customListDefDef != null) {
673             customListDefDef.delete();
674           }
675           if (groupTypeDef != null) {
676             groupTypeDef.delete();
677           }
678           
679           sw.stop();
680           EventLog.info(s, M.GROUPTYPE_DEL + Quote.single(typeName), sw);
681           // Now update the cached types + fields
682           GroupTypeFinder.internal_updateKnownTypes();
683           FieldFinder.internal_updateKnownFields();
684 
685           if (!hibernateHandlerBean.isCallerWillCreateAudit()) {
686             AuditEntryit/AuditEntry.html#AuditEntry">AuditEntry auditEntry = new AuditEntry(AuditTypeBuiltin.GROUP_TYPE_DELETE, "id", 
687                 GroupType.this.getUuid(), "name", GroupType.this.getName());
688             auditEntry.setDescription("Deleted group type: " + GroupType.this.getName());
689             auditEntry.saveOrUpdate(true);
690           }
691         }
692         catch (GrouperDAOException eDAO) {
693           String msg = E.GROUPTYPE_DEL + eDAO.getMessage();
694           LOG.error(msg);
695           throw new SchemaException(msg, eDAO);
696         }
697         return null;
698       }});
699   } // public void delete(s)
700 
701   /** logger */
702   private static final Log LOG = GrouperUtil.getLog(GroupType.class);
703 
704   /**
705    * Delete a custom {@link Field} from a custom {@link GroupType}.
706    * <p/>
707    * Delete a field from this group type.  If the field does not exist
708    * in this type a {@link SchemaException} will be thrown.  If the
709    * subject is not root-like, an {@link InsufficientPrivilegeException}
710    * will be thrown.
711    * <pre class="eg">
712    * try {
713    *   type.deleteField(s, "my field");
714    *   );
715    * }
716    * catch (InsufficientPrivilegeException eIP) {
717    *   // Not privileged to delete field
718    * }
719    * catch (SchemaException eS) {
720    *   // Invalid schema
721    * }
722    * </pre>
723    * @param   s         Delete field within this session context.
724    * @param   name      Name of field to delete.
725    * @throws  InsufficientPrivilegeException
726    * @throws  SchemaException
727    * @deprecated
728    */
729   public void deleteField(final GrouperSession s, final String name)
730       throws  InsufficientPrivilegeException, SchemaException {
731 
732     HibernateSession.callbackHibernateSession(
733         GrouperTransactionType.READ_WRITE_OR_USE_EXISTING, AuditControl.WILL_AUDIT, new HibernateHandler() {
734 
735       public Object callback(HibernateHandlerBean hibernateHandlerBean)
736           throws GrouperDAOException {
737         
738         try {
739           //note, no need for GrouperSession inverse of control
740           StopWatch sw  = new StopWatch();
741           sw.start();
742           Field     field   = FieldFinder.find(name, true);  
743           ModifyGroupTypeValidator          vModify = ModifyGroupTypeValidator.validate(s, GroupType.this);
744           if (vModify.isInvalid()) {
745             throw new InsufficientPrivilegeException( vModify.getErrorMessage() );
746           }
747           DeleteFieldFromGroupTypeValidator vDelete = DeleteFieldFromGroupTypeValidator.validate(GroupType.this, field);
748           if (vDelete.isInvalid()) {
749             throw new SchemaException( vDelete.getErrorMessage() );
750           }
751           if ( GrouperDAOFactory.getFactory().getField().isInUse(field) ) {
752             String msg = E.GROUPTYPE_FIELDNODELINUSE + name;
753             LOG.error( msg);
754             throw new SchemaException(msg);
755           }
756           Set fields = GroupType.this.getFields();
757           if ( fields.remove( field ) ) {
758             GroupType.this.setFields(fields);
759             String typeString = field.getTypeString();
760             GrouperDAOFactory.getFactory().getField().delete(field);
761             
762             String stemName = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.baseStem");
763             String groupTypeDefPrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.groupTypeDef.prefix");
764             AttributeDef groupTypeDef = AttributeDefFinder.findByName(stemName + ":" + groupTypeDefPrefix + GroupType.this.name, true);
765             String customListPrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.customList.prefix");
766             AttributeDefName customList = AttributeDefNameFinder.findByName(stemName + ":" + customListPrefix + GroupType.this.name, false);
767             groupTypeDef.getAttributeValueDelegate().deleteValue(customList.getName(), field.getUuid());
768             
769             if (!hibernateHandlerBean.isCallerWillCreateAudit()) {
770               //only audit if actually changed the type
771               AuditEntryit/AuditEntry.html#AuditEntry">AuditEntry auditEntry = new AuditEntry(AuditTypeBuiltin.GROUP_FIELD_DELETE, "id", 
772                   field.getUuid(), "name", field.getName(), "groupTypeId", GroupType.this.getUuid(), "groupTypeName", GroupType.this.getName(), "type", typeString);
773               auditEntry.setDescription("Deleted group field: " + name + ", id: " + field.getUuid() + ", type: " + typeString + ", groupType: " + GroupType.this.getName());
774               auditEntry.saveOrUpdate(true);
775             }
776             
777             sw.stop();
778             EventLog.info(
779               s,
780               M.GROUPTYPE_DELFIELD + Quote.single(field.getName()) + " type=" + Quote.single( GroupType.this.getName() ),
781               sw
782             );
783           }
784           else {
785             String msg = E.GROUPTYPE_FIELDNODELMISS;
786             LOG.error( msg);
787             throw new SchemaException(msg);
788           }
789           
790           FieldFinder.clearCache();
791         } catch (GrouperDAOException eDAO) {
792           String msg = E.GROUPTYPE_FIELDDEL + name + ": " + eDAO.getMessage();
793           LOG.error( msg);
794           throw new SchemaException(msg, eDAO);
795         }
796         return null;
797       }        
798     });
799   }
800 
801   /**
802    * 
803    * @return true if system type
804    */
805   public boolean isSystemType() {
806     return false;
807   } 
808   
809 
810   /**
811    * 
812    * @param s
813    * @param name
814    * @param exceptionIfExists
815    * @param changed boolean array, the fisrt index will be in it existed already
816    * @param uuid to use or null for one to be assigned
817    * @return the type
818    * @throws InsufficientPrivilegeException
819    * @throws SchemaException
820    */
821   public static GroupType internal_createType(
822     final GrouperSession s, final String name, final boolean exceptionIfExists, final boolean[] changed, String uuid)
823       throws  InsufficientPrivilegeException,
824               SchemaException { 
825     
826     final String UUID = StringUtils.isBlank(uuid) ? GrouperUuid.getUuid() : uuid;
827     
828     return (GroupType)HibernateSession.callbackHibernateSession(
829         GrouperTransactionType.READ_WRITE_OR_USE_EXISTING, AuditControl.WILL_AUDIT, new HibernateHandler() {
830 
831       public Object callback(HibernateHandlerBean hibernateHandlerBean)
832           throws GrouperDAOException {
833         try {
834           //note, no need for GrouperSession inverse of control
835           if (!PrivilegeHelper.isRoot(s)) {
836             String msg = "subject '" + GrouperUtil.subjectToString(s.getSubject()) + "' not privileged to add group types ('" + name + "')";
837             LOG.error( msg);
838             throw new InsufficientPrivilegeException(msg);
839           }
840           
841           @SuppressWarnings("deprecation")
842           GroupType existing = GroupTypeFinder.find(name, false);
843 
844           if (GrouperUtil.length(changed) >= 1) {
845             changed[0] = true;
846           }
847           if (existing != null) {
848             if (GrouperUtil.length(changed) >= 1) {
849               changed[0] = false;
850             }
851             if (exceptionIfExists) {
852               String msg = E.GROUPTYPE_EXISTS + name;
853               LOG.error( msg);
854               throw new SchemaException(msg);
855             }
856 
857             return existing;
858           }
859           
860           String stemName = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.baseStem");
861           String groupTypeDefPrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.groupTypeDef.prefix");
862           String groupTypePrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.groupType.prefix");
863           
864           Stem stem = GrouperDAOFactory.getFactory().getStem().findByName(stemName, true);
865           AttributeDef groupTypeDef = stem.addChildAttributeDef(groupTypeDefPrefix + name, AttributeDefType.attr);
866           groupTypeDef.setAssignToGroup(true);
867           groupTypeDef.store();
868           
869           AttributeDefName groupType = stem.internal_addChildAttributeDefName(s, groupTypeDef, groupTypePrefix + name, groupTypePrefix + name, UUID, null);
870                       
871           if (!hibernateHandlerBean.isCallerWillCreateAudit()) {
872             //only audit if actually changed the type
873             AuditEntryit/AuditEntry.html#AuditEntry">AuditEntry auditEntry = new AuditEntry(AuditTypeBuiltin.GROUP_TYPE_ADD, "id", 
874                 groupType.getId(), "name", groupType.getName());
875             auditEntry.setDescription("Added group type: " + groupType.getName());
876             auditEntry.saveOrUpdate(true);
877           }
878           
879           return GroupType.internal_getGroupType(groupType, true);
880         } catch (GrouperDAOException eDAO) {
881           String msg = E.GROUPTYPE_ADD + name + ": " + eDAO.getMessage();
882           LOG.error( msg);
883           throw new SchemaException(msg, eDAO);
884         }
885       }
886       
887     });
888 
889   }
890 
891 
892   /**
893    * 
894    * @see java.lang.Object#equals(java.lang.Object)
895    */
896   public boolean equals(Object other) {
897     if (this == other) {
898       return true;
899     }
900     if (!(other instanceof GroupType)) {
901       return false;
902     }
903     GroupType./../../../edu/internet2/middleware/grouper/GroupType.html#GroupType">GroupType that = (GroupType) other;
904     return new EqualsBuilder()
905       .append( this.name, that.name )
906       .isEquals();
907   }
908 
909 
910   /**
911    * @return create time
912    * @since   1.2.0
913    */ 
914   public long getCreateTime() {
915     return this.createTime;
916   }
917 
918 
919   /**
920    * @return fields
921    * @since   1.2.0
922    */ 
923   public Set<Field> getFields() {
924     if (this.fields == null) {
925       this.fields = FieldFinder.findAllByGroupType(this);
926     }
927     return this.fields;
928   }
929 
930   /**
931    * @return name
932    * @since   1.2.0
933    */ 
934   public String getName() {
935     return this.name;
936   }
937 
938 
939   /**
940    * @return uuid
941    * @since   1.2.0
942    */ 
943   public String getUuid() {
944     return this.uuid;
945   }
946 
947 
948   /**
949    * @return hash code
950    * @since   1.2.0
951    */
952   public int hashCode() {
953     return new HashCodeBuilder()
954       .append( this.name )
955       .toHashCode();
956   } // public int hashCode()
957 
958 
959   /**
960    * @param createTime 
961    * @since   1.2.0
962    */ 
963   public void setCreateTime(long createTime) {
964     this.createTime = createTime;
965   
966   }
967 
968 
969   /**
970    * @param fields 
971    * @since   1.2.0
972    */ 
973   public void setFields(Set fields) {
974     this.fields = fields;
975   
976   }
977 
978   /**
979    * @param name 
980    * @since   1.2.0
981    */ 
982   public void setName(String name) {
983     this.name = name;
984   
985   }
986 
987 
988   /**
989    * @param uuid 
990    * @since   1.2.0
991    */ 
992   public void setUuid(String uuid) {
993     this.uuid = uuid;
994   
995   }
996 
997 
998   /**
999    * @return string
1000    * @since   1.2.0
1001    */
1002   @Override
1003   public String toString() {
1004     return new ToStringBuilder(this)
1005       .append( "createTime",   this.getCreateTime()   )
1006       .append( "fields",       GrouperUtil.length(this.getFields()))
1007       .append( "name",         this.getName()         )
1008       .append( "uuid",         this.getUuid()         )
1009       .toString();
1010   }
1011 
1012   /**
1013    * deep clone the fields in this object
1014    */
1015   @Override
1016   public GroupType clone() {
1017     return GrouperUtil.clone(this, CLONE_FIELDS);
1018   }
1019 
1020   /**
1021    * @see java.lang.Comparable#compareTo(java.lang.Object)
1022    */
1023   public int compareTo(Object o) {
1024     if (!(o instanceof GroupType)) {
1025       return -1;
1026     }
1027     String thisName = StringUtils.defaultString(this.name);
1028     String otherName = StringUtils.defaultString(((GroupType)o).name);
1029     return thisName.compareTo(otherName);
1030   }
1031   
1032   /**
1033    * @return attributeDefName that corresponds to this group type
1034    */
1035   public AttributeDefName getAttributeDefName() {
1036     
1037     AttributeDefName attributeDefName = attributeDefNameFromTypeIdCache().get(this.uuid);
1038     
1039     if (attributeDefName == null) {
1040       attributeDefName = AttributeDefNameFinder.findByIdAsRoot(this.uuid, true);
1041       if (attributeDefName != null) {
1042         //put this in the root cache
1043         Hib3AttributeDefNameDAO.attributeDefNameCacheAsRootIdsAndNamesAdd(attributeDefName);
1044       }
1045       attributeDefNameFromTypeIdCache().put(this.uuid, attributeDefName);
1046     }
1047     
1048     return attributeDefName;
1049   }
1050   
1051   /**
1052    * @param attributeDefName1
1053    */
1054   public void internalSetAttributeDefName(AttributeDefName attributeDefName1) {
1055     
1056     if (attributeDefName1 != null) {
1057       if (!StringUtils.equals(this.uuid, attributeDefName1.getId())) {
1058         throw new RuntimeException("Why does the groupType id " 
1059             + this.uuid + " not equal the param id: " + attributeDefName1.getId());
1060       }
1061     }
1062     attributeDefNameFromTypeIdCache().put(this.uuid, attributeDefName1);
1063     
1064   }
1065 
1066   /**
1067    * @param attribute
1068    * @param exceptionIfNotLegacyGroupType 
1069    * @return groupType
1070    */
1071   public static GroupType internal_getGroupType(AttributeDefName attribute, boolean exceptionIfNotLegacyGroupType) {
1072     String stemName = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.baseStem");
1073     String groupTypePrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.groupType.prefix");
1074     
1075     if (!attribute.getName().startsWith(stemName + ":" + groupTypePrefix)) {
1076       if (exceptionIfNotLegacyGroupType) {
1077         throw new RuntimeException("AttributeDefName " + attribute.getName() + " is not a legacy group type.");
1078       }
1079       
1080       return null;
1081     }
1082     
1083     GroupTypeouper/GroupType.html#GroupType">GroupType gt = new GroupType();
1084     gt.setContextId(attribute.getContextId());
1085     gt.setCreateTime(attribute.getCreatedOnDb());
1086     gt.setHibernateVersionNumber(attribute.getHibernateVersionNumber());
1087     gt.setName(attribute.getExtension().substring(groupTypePrefix.length()));
1088     gt.setUuid(attribute.getId());
1089     gt.internalSetAttributeDefName(attribute);
1090     
1091     return gt;
1092   }
1093   
1094   /**
1095    * @return the attributeDef for attribute assignments
1096    */
1097   public AttributeDef internal_getAttributeDefForAttributes() {
1098     String stemName = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.baseStem");
1099     String attributeDefPrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.attributeDef.prefix");
1100     AttributeDef attributeDef = AttributeDefFinder.findByName(stemName + ":" + attributeDefPrefix + GroupType.this.name, false);
1101     
1102     return attributeDef;
1103   }
1104   
1105   /**
1106    * @return the attributeDef for custom lists
1107    */
1108   public AttributeDef internal_getAttributeDefForCustomLists() {
1109     String stemName = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.baseStem");    
1110     String customListDefPrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.customListDef.prefix");
1111     AttributeDef customListDef = AttributeDefFinder.findByName(stemName + ":" + customListDefPrefix + GroupType.this.name, false);    
1112     
1113     return customListDef;
1114   }
1115   
1116   /**
1117    * @return the attributeDefName for custom lists
1118    */
1119   public AttributeDefName internal_getAttributeDefNameForCustomLists() {
1120     String stemName = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.baseStem");    
1121     String customListPrefix = GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.customList.prefix");
1122     AttributeDefName customList = AttributeDefNameFinder.findByName(stemName + ":" + customListPrefix + GroupType.this.name, false);
1123 
1124     return customList;
1125   }
1126   
1127   /**
1128    * @return legacy attributes
1129    */
1130   public Set<AttributeDefName> getLegacyAttributes() {
1131     
1132     Set<AttributeDefName> legacyAttributes = legacyAttributesFromTypeIdCache().get(this.uuid);
1133     
1134     if (legacyAttributes == null) {
1135       AttributeDef attributeDefForAttributes = this.internal_getAttributeDefForAttributes();
1136       
1137       if (attributeDefForAttributes != null) {
1138         legacyAttributes = GrouperDAOFactory.getFactory().getAttributeDefName().findByAttributeDef(attributeDefForAttributes.getId());
1139       } else {
1140         legacyAttributes = new LinkedHashSet<AttributeDefName>();
1141       }
1142       
1143       legacyAttributesFromTypeIdCache().put(this.uuid, legacyAttributes);
1144     }
1145     return legacyAttributes;
1146   }
1147 }