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   * @author mchyzer
18   * $Id: GrouperCheckConfig.java,v 1.35 2009-12-10 08:54:15 mchyzer Exp $
19   */
20  package edu.internet2.middleware.grouper.misc;
21  
22  import static edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowConfigAttributeNames.GROUPER_WORKFLOW_CONFIG_APPROVALS;
23  import static edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowConfigAttributeNames.GROUPER_WORKFLOW_CONFIG_ATTRIBUTE_NAME;
24  import static edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowConfigAttributeNames.GROUPER_WORKFLOW_CONFIG_DEF;
25  import static edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowConfigAttributeNames.GROUPER_WORKFLOW_CONFIG_DESCRIPTION;
26  import static edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowConfigAttributeNames.GROUPER_WORKFLOW_CONFIG_ENABLED;
27  import static edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowConfigAttributeNames.GROUPER_WORKFLOW_CONFIG_FORM;
28  import static edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowConfigAttributeNames.GROUPER_WORKFLOW_CONFIG_ID;
29  import static edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowConfigAttributeNames.GROUPER_WORKFLOW_CONFIG_NAME;
30  import static edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowConfigAttributeNames.GROUPER_WORKFLOW_CONFIG_PARAMS;
31  import static edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowConfigAttributeNames.GROUPER_WORKFLOW_CONFIG_SEND_EMAIL;
32  import static edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowConfigAttributeNames.GROUPER_WORKFLOW_CONFIG_TYPE;
33  import static edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowConfigAttributeNames.GROUPER_WORKFLOW_CONFIG_VALUE_DEF;
34  import static edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowConfigAttributeNames.GROUPER_WORKFLOW_CONFIG_VIEWERS_GROUP_ID;
35  
36  import java.io.File;
37  import java.net.URL;
38  import java.sql.Connection;
39  import java.sql.DriverManager;
40  import java.sql.SQLException;
41  import java.util.HashSet;
42  import java.util.Map;
43  import java.util.Properties;
44  import java.util.Set;
45  import java.util.jar.Attributes;
46  import java.util.jar.Attributes.Name;
47  import java.util.jar.Manifest;
48  import java.util.regex.Matcher;
49  import java.util.regex.Pattern;
50  
51  import org.apache.commons.lang.StringUtils;
52  import org.apache.commons.lang.exception.ExceptionUtils;
53  import org.apache.commons.logging.Log;
54  import org.quartz.Job;
55  
56  import edu.internet2.middleware.grouper.Group;
57  import edu.internet2.middleware.grouper.GroupFinder;
58  import edu.internet2.middleware.grouper.GroupSave;
59  import edu.internet2.middleware.grouper.GrouperSession;
60  import edu.internet2.middleware.grouper.Stem;
61  import edu.internet2.middleware.grouper.StemFinder;
62  import edu.internet2.middleware.grouper.StemSave;
63  import edu.internet2.middleware.grouper.SubjectFinder;
64  import edu.internet2.middleware.grouper.app.attestation.GrouperAttestationJob;
65  import edu.internet2.middleware.grouper.app.deprovisioning.GrouperDeprovisioningAffiliation;
66  import edu.internet2.middleware.grouper.app.deprovisioning.GrouperDeprovisioningAttributeNames;
67  import edu.internet2.middleware.grouper.app.deprovisioning.GrouperDeprovisioningAttributeValue;
68  import edu.internet2.middleware.grouper.app.deprovisioning.GrouperDeprovisioningConfiguration;
69  import edu.internet2.middleware.grouper.app.deprovisioning.GrouperDeprovisioningJob;
70  import edu.internet2.middleware.grouper.app.deprovisioning.GrouperDeprovisioningOverallConfiguration;
71  import edu.internet2.middleware.grouper.app.deprovisioning.GrouperDeprovisioningSettings;
72  import edu.internet2.middleware.grouper.app.grouperTypes.GrouperObjectTypesAttributeNames;
73  import edu.internet2.middleware.grouper.app.grouperTypes.GrouperObjectTypesSettings;
74  import edu.internet2.middleware.grouper.app.loader.GrouperLoader;
75  //import edu.internet2.middleware.grouper.app.deprovisioning.GrouperDeprovisioningJob;
76  import edu.internet2.middleware.grouper.app.loader.GrouperLoaderConfig;
77  import edu.internet2.middleware.grouper.app.loader.NotificationDaemon;
78  import edu.internet2.middleware.grouper.app.loader.ldap.LoaderLdapUtils;
79  import edu.internet2.middleware.grouper.app.provisioning.GrouperProvisioningAttributeNames;
80  import edu.internet2.middleware.grouper.app.provisioning.GrouperProvisioningSettings;
81  import edu.internet2.middleware.grouper.app.reports.GrouperReportConfigAttributeNames;
82  import edu.internet2.middleware.grouper.app.reports.GrouperReportInstanceAttributeNames;
83  import edu.internet2.middleware.grouper.app.reports.GrouperReportSettings;
84  import edu.internet2.middleware.grouper.app.serviceLifecycle.GrouperRecentMemberships;
85  import edu.internet2.middleware.grouper.app.upgradeTasks.UpgradeTasksJob;
86  import edu.internet2.middleware.grouper.app.usdu.UsduAttributeNames;
87  import edu.internet2.middleware.grouper.app.usdu.UsduSettings;
88  import edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowInstanceAttributeNames;
89  import edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowSettings;
90  import edu.internet2.middleware.grouper.attr.AttributeDef;
91  import edu.internet2.middleware.grouper.attr.AttributeDefName;
92  import edu.internet2.middleware.grouper.attr.AttributeDefSave;
93  import edu.internet2.middleware.grouper.attr.AttributeDefType;
94  import edu.internet2.middleware.grouper.attr.AttributeDefValueType;
95  import edu.internet2.middleware.grouper.attr.assign.AttributeAssignResult;
96  import edu.internet2.middleware.grouper.attr.finder.AttributeDefFinder;
97  import edu.internet2.middleware.grouper.attr.finder.AttributeDefNameFinder;
98  import edu.internet2.middleware.grouper.audit.GrouperEngineBuiltin;
99  import edu.internet2.middleware.grouper.cfg.GrouperConfig;
100 import edu.internet2.middleware.grouper.cfg.GrouperHibernateConfig;
101 import edu.internet2.middleware.grouper.cfg.dbConfig.ConfigFileMetadata;
102 import edu.internet2.middleware.grouper.cfg.dbConfig.ConfigFileName;
103 import edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerBase;
104 import edu.internet2.middleware.grouper.ddl.GrouperDdlUtils;
105 import edu.internet2.middleware.grouper.entity.EntityUtils;
106 import edu.internet2.middleware.grouper.exception.GrouperSessionException;
107 import edu.internet2.middleware.grouper.exception.InsufficientPrivilegeException;
108 import edu.internet2.middleware.grouper.exception.MemberAddException;
109 import edu.internet2.middleware.grouper.exception.SessionException;
110 import edu.internet2.middleware.grouper.externalSubjects.ExternalSubjectAttrFramework;
111 import edu.internet2.middleware.grouper.group.TypeOfGroup;
112 import edu.internet2.middleware.grouper.hibernate.GrouperContext;
113 import edu.internet2.middleware.grouper.hooks.AttributeAssignHooks;
114 import edu.internet2.middleware.grouper.hooks.AttributeAssignValueHooks;
115 import edu.internet2.middleware.grouper.hooks.AttributeDefHooks;
116 import edu.internet2.middleware.grouper.hooks.AttributeDefNameHooks;
117 import edu.internet2.middleware.grouper.hooks.AttributeHooks;
118 import edu.internet2.middleware.grouper.hooks.CompositeHooks;
119 import edu.internet2.middleware.grouper.hooks.ExternalSubjectHooks;
120 import edu.internet2.middleware.grouper.hooks.FieldHooks;
121 import edu.internet2.middleware.grouper.hooks.GroupHooks;
122 import edu.internet2.middleware.grouper.hooks.GroupTypeHooks;
123 import edu.internet2.middleware.grouper.hooks.GroupTypeTupleHooks;
124 import edu.internet2.middleware.grouper.hooks.GrouperSessionHooks;
125 import edu.internet2.middleware.grouper.hooks.LifecycleHooks;
126 import edu.internet2.middleware.grouper.hooks.LoaderHooks;
127 import edu.internet2.middleware.grouper.hooks.MemberHooks;
128 import edu.internet2.middleware.grouper.hooks.MembershipHooks;
129 import edu.internet2.middleware.grouper.hooks.StemHooks;
130 import edu.internet2.middleware.grouper.hooks.examples.AttributeAutoCreateHook;
131 import edu.internet2.middleware.grouper.hooks.examples.AttributeDefNameUniqueNameCaseInsensitiveHook;
132 import edu.internet2.middleware.grouper.hooks.examples.AttributeDefUniqueNameCaseInsensitiveHook;
133 import edu.internet2.middleware.grouper.hooks.examples.GroupUniqueNameCaseInsensitiveHook;
134 import edu.internet2.middleware.grouper.hooks.examples.MembershipCannotAddSelfToGroupHook;
135 import edu.internet2.middleware.grouper.hooks.examples.MembershipOneInFolderMaxHook;
136 import edu.internet2.middleware.grouper.hooks.examples.StemUniqueNameCaseInsensitiveHook;
137 import edu.internet2.middleware.grouper.instrumentation.InstrumentationDataUtils;
138 import edu.internet2.middleware.grouper.internal.dao.QueryOptions;
139 import edu.internet2.middleware.grouper.internal.dao.hib3.Hib3AttributeDefDAO;
140 import edu.internet2.middleware.grouper.internal.dao.hib3.Hib3AttributeDefNameDAO;
141 import edu.internet2.middleware.grouper.messaging.GrouperBuiltinMessagingSystem;
142 import edu.internet2.middleware.grouper.permissions.limits.PermissionLimitUtils;
143 import edu.internet2.middleware.grouper.privs.AttributeDefPrivilege;
144 import edu.internet2.middleware.grouper.rules.RuleUtils;
145 import edu.internet2.middleware.grouper.ui.customUi.CustomUiAttributeNames;
146 import edu.internet2.middleware.grouper.ui.util.GrouperUiConfigInApi;
147 import edu.internet2.middleware.grouper.userData.GrouperUserDataUtils;
148 import edu.internet2.middleware.grouper.util.GrouperUtil;
149 import edu.internet2.middleware.grouperClient.util.ExpirableCache;
150 import edu.internet2.middleware.morphString.Morph;
151 import edu.internet2.middleware.morphString.MorphStringConfig;
152 import edu.internet2.middleware.subject.Subject;
153 import edu.internet2.middleware.subject.SubjectCheckConfig;
154 import edu.internet2.middleware.subject.SubjectNotFoundException;
155 import edu.internet2.middleware.subject.SubjectNotUniqueException;
156 
157 
158 /**
159  * check the configuration of grouper to make sure things are configured right, and
160  * to give descriptive errors of the problems
161  */
162 public class GrouperCheckConfig {
163 
164   /**
165    * we can delay some config until after started, but maybe some things need to wait for it
166    */
167   private static boolean doneWithExtraConfig = false;
168   
169   /**
170    * 
171    * @return true when done with extra config
172    */
173   public static boolean isDoneWithExtraconfig() {
174     return doneWithExtraConfig;
175   }
176 
177   /**
178    * 
179    */
180   public static void waitUntilDoneWithExtraConfig() {
181     while (!doneWithExtraConfig) {
182       GrouperUtil.sleep(1000);
183     }
184   }
185   
186   /**
187    * 
188    */
189   public static final String GROUPER_PROPERTIES_NAME = "grouper.properties";
190 
191   /**
192    * logger 
193    */
194   private static final Log LOG = GrouperUtil.getLog(GrouperCheckConfig.class);
195   
196   /** result from check group */
197   public static enum CheckGroupResult{ 
198     /** group didnt exist, and was created */
199     DIDNT_CHECK, 
200 
201     /** group didnt exist, and was created */
202     CREATED, 
203     
204     /** group doesnt exist */
205     DOESNT_EXIST, 
206     
207     /** group created */
208     ERROR_CREATING, 
209     
210     /** group exists */
211     EXISTS };
212   
213   /**
214    * verify that a group exists by name (dont throw exceptions)
215    * @param grouperSession (probably should be root session)
216    * @param groupName
217    * @param logError 
218    * @param autoCreate if auto create, or null, for grouper.properties setting
219    * @param logAutocreate 
220    * @param displayExtension optional, dislpay extension if creating
221    * @param groupDescription group description if auto create
222    * @param propertyDescription for logging explaning to the user how to fix the problem
223    * @param groupResult put in an array of size one to get the group back
224    * @return if group exists or not or was created
225    */
226   public static CheckGroupResult checkGroup(GrouperSession grouperSession, String groupName, 
227       boolean logError, Boolean autoCreate, 
228       boolean logAutocreate, String displayExtension, String groupDescription, String propertyDescription,
229       Group[] groupResult) {
230 
231     if (configCheckDisabled()) {
232       return CheckGroupResult.DIDNT_CHECK;
233     }
234     try {
235       Group group = GroupFinder.findByName(grouperSession, groupName, true, new QueryOptions().secondLevelCache(false));
236       if (group != null) {
237         if (GrouperUtil.length(groupResult) >= 1) {
238           groupResult[0] = group;
239         }
240         GroupFinder.groupCacheAsRootAddSystemGroup(group);
241         return CheckGroupResult.EXISTS;
242       }
243     } catch (Exception e) {
244       
245     }
246     
247     if (logError) {
248       String error = "cannot find group from config: " + propertyDescription + ": " + groupName;
249       System.err.println("Grouper warning: " + error);
250       LOG.warn(error);
251     }
252     
253     //get auto create from config
254     if (autoCreate == null) {
255       Properties properties = GrouperConfig.retrieveConfig().properties();
256       autoCreate = GrouperUtil.propertiesValueBoolean(properties, GrouperConfig.retrieveConfig().propertiesOverrideMap(), 
257           "configuration.autocreate.system.groups", false);
258     }
259     
260     if (autoCreate) {
261       try {
262         Group group = Group.saveGroup(grouperSession, null, null, groupName, displayExtension, groupDescription, null, true);
263         if (GrouperUtil.length(groupResult) >= 1) {
264           groupResult[0] = group;
265           GroupFinder.groupCacheAsRootAddSystemGroup(group);
266         }
267         if (logAutocreate) {
268           String error = "auto-created " + propertyDescription + ": " + groupName;
269           System.err.println("Grouper note: " + error);
270           LOG.warn(error);
271         }
272         return CheckGroupResult.CREATED;
273       } catch (Exception e) {
274         System.err.println("Grouper error: " + groupName + ", " + ExceptionUtils.getFullStackTrace(e));
275         LOG.error("Problem with group: " + groupName, e);
276         return CheckGroupResult.ERROR_CREATING;
277       }
278     }
279     
280     return CheckGroupResult.DOESNT_EXIST;
281   }
282 
283   /**
284    * check a jar
285    * @param name name of the jar from grouper
286    * @param size that the jar should be
287    * @param sampleClassName inside the jar
288    * @param manifestVersion in the manifest file, which version we are expecting
289    */
290   public static void checkJar(String name, long size, String sampleClassName, String manifestVersion) {
291     checkJar(name, GrouperUtil.toSet(size), sampleClassName, manifestVersion);
292   }
293 
294   /**
295    * check a jar
296    * @param name name of the jar from grouper
297    * @param sizes that the jar should be
298    * @param sampleClassName inside the jar
299    * @param manifestVersion in the manifest file, which version we are expecting
300    */
301   public static void checkJar(String name, Set<Long> sizes, String sampleClassName, String manifestVersion) {
302     
303     if (configCheckDisabled()) {
304       return;
305     }
306     
307     Class sampleClass = null;
308     try {
309       sampleClass = Class.forName(sampleClassName);
310     } catch (ClassNotFoundException cnfe) {
311       String error = "cannot find class " + sampleClassName + ", perhaps you are missing jar: " + name;
312       System.err.println("Grouper warning: " + error);
313       LOG.warn(error);
314       return;
315     }
316     String jarFileFullName = null;
317     String jarFileName = null;
318     String jarVersion = null;
319     long jarFileSize = -1;
320     try {
321       
322       File jarFile = GrouperUtil.jarFile(sampleClass, true);
323       jarFileFullName = jarFile.getCanonicalPath();
324       jarFileName = jarFile.getName();
325       jarFileSize = jarFile.length();
326       //in case null
327       jarVersion = jarVersion(sampleClass) + "";
328       
329       if (sizes.contains(jarFileSize) && StringUtils.equals(manifestVersion, jarVersion)
330           && StringUtils.equals(name, jarFile.getName())) {
331         LOG.debug("Found jarfile: " + jarFileFullName + " with correct size " 
332           + GrouperUtil.toStringForLog(sizes) + " and version: " + manifestVersion);
333         return;
334       }
335       
336     } catch (Exception e) {
337       //LOG.error("Error finding jar: " + name, e);
338       //e.printStackTrace();
339       //having problems
340     }
341     
342     String error = "jarfile mismatch, expecting name: '" + name + "' size: " + GrouperUtil.toStringForLog(sizes)
343       + " manifest version: " + manifestVersion + ".  However the jar detected is: "
344       + jarFileFullName + ", name: " + jarFileName + " size: " + jarFileSize
345       + " manifest version: " + jarVersion;
346     System.err.println("Grouper warning: " + error);
347     LOG.warn(error);
348   }
349 
350   /**
351    * make sure a resource is on the resource path
352    * @param resourcePath
353    * @return false if problem or if not checking configs
354    */
355   public static boolean checkResource(String resourcePath) {
356     return checkResource(resourcePath, true);
357   }
358 
359   /**
360    * make sure a resource is on the resource path
361    * @param resourcePath
362    * @param required
363    * @return false if problem or if not checking configs
364    */
365   public static boolean checkResource(String resourcePath, boolean required) {
366     if (configCheckDisabled()) {
367       return false;
368     }
369     try {
370       URL url = GrouperUtil.computeUrl(resourcePath, false);
371       if (url != null) {
372         LOG.debug("Found resource: " + url);
373         return true;
374       }
375     } catch (Exception e) {
376       //this means it cant be found
377     }
378     if (!required) {
379       return false;
380     }
381     String error = "Cant find required resource on classpath: " + resourcePath;
382     //this is serious, lets go out and error
383     System.err.println("Grouper error: " + error);
384     LOG.error(error);
385     return false;
386   }
387 
388   /** cache if we are disabling config check */
389   private static Boolean disableConfigCheck = null;
390   
391   /**
392    * if the config check is disabled
393    * @return if the config check is disabled
394    */
395   public static boolean configCheckDisabled() {
396     if (disableConfigCheck == null) {
397       //see if we shouldnt do this (but dont use ApiConfig API)
398       try {
399         Properties properties = GrouperConfig.retrieveConfig().properties();
400         String detectErrorsKey = "configuration.detect.errors";
401         String detectErrors = GrouperUtil.propertiesValue(properties, detectErrorsKey);
402         if (!GrouperUtil.booleanValue(detectErrors, true)) {
403           String warning = "Not checking configuration integrity due to grouper.properties: " 
404               + detectErrorsKey;
405           System.err.println("Grouper warning: " + warning);
406           LOG.warn(warning);
407           disableConfigCheck = true;
408         }
409       } catch (Exception e) {
410         //cant read grouper properties
411       }
412       if (disableConfigCheck == null) {
413         disableConfigCheck = false;
414       }
415     }
416     return disableConfigCheck;
417   }
418 
419   private static void verifyMailConfigsMigrated() {
420     GrouperConfig grouperConfig = GrouperConfig.retrieveConfig();
421 
422     String[] oldConfigs = new String[] {"mail.transport.protocol", "mail.use.protocol.in.property.names", "mail.from.address", "mail.subject.prefix", "mail.sendAllMessagesHere", "mail.debug", "grouperEmailContentType"};
423     String[] newConfigs = new String[] {"mail.smtp.transport.protocol", "mail.smtp.use.protocol.in.property.names", "mail.smtp.from.address", "mail.smtp.subject.prefix", "mail.smtp.sendAllMessagesHere", "mail.smtp.debug", "mail.smtp.grouperEmailContentType"};
424     
425     for (int i=0;i<oldConfigs.length;i++) {
426       if (!StringUtils.isBlank(grouperConfig.propertyValueString(oldConfigs[i]))) {
427         LOG.error("Error: please change your grouper.properties config key: " + oldConfigs[i] + " to be " + newConfigs[i]);
428       }
429     }
430 
431   }
432   
433   /**
434    * make sure grouper config files exist
435    */
436   private static void checkGrouperConfigs() {
437     
438     //make sure config files are there
439     checkGrouperConfig();
440     checkResource("grouper.cache.properties");
441     checkResource("grouper.hibernate.properties");
442     checkResource("log4j.properties");
443     checkResource("morphString.properties");
444     checkResource("subject.properties");
445     
446     verifyMailConfigsMigrated();
447     
448     for (ConfigFileName configFileName : ConfigFileName.values()) {
449       if (!configFileName.isUseBaseForConfigFileMetadata()) {
450         continue;
451       }
452       ConfigFileMetadata configFileMetadata = configFileName.configFileMetadata();
453       // i.e. the ui and ws will be null if running gsh alone
454       if (configFileMetadata != null) {
455         if (!configFileMetadata.isValidConfig()) {
456           LOG.error("Config " + configFileName.getClasspath() + " is not valid, see logs");
457         }
458       }
459     }
460     
461   }
462   
463   /**
464    * go through each property and check types of values
465    */
466   private static void checkGrouperConfig() {
467     //if (!checkResource(GROUPER_PROPERTIES_NAME)) {
468     //  return;
469     //}
470 
471     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("groups.create.grant.all.optin", true);
472     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("groups.create.grant.all.optout", true);
473     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("groups.create.grant.all.read", true);
474     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("groups.create.grant.all.view", true);
475     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("groups.create.grant.all.groupAttrRead", true);
476 
477     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("stems.create.grant.all.create", true);
478     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("stems.create.grant.all.stemAdmin", true);
479     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("stems.create.grant.all.stemAttrRead", true);
480     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("stems.create.grant.all.stemAttrUpdate", true);
481 
482     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("groups.wheel.use", true);
483 
484     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("registry.autoinit", true);
485     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("configuration.detect.errors", true);
486     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("configuration.display.startup.message", true);
487 
488     GrouperConfig.retrieveConfig().assertPropertyValueClass("dao.factory", 
489         GrouperDAOFactory.class, true);
490 
491     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.attribute.class", AttributeHooks.class, false);
492     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.attributeDef.class", AttributeDefHooks.class, false);
493     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.attributeDefName.class", AttributeDefNameHooks.class, false);
494     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.attributeAssign.class", AttributeAssignHooks.class, false);
495     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.attributeAssignValue.class", AttributeAssignValueHooks.class, false);
496     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.composite.class", CompositeHooks.class, false);
497     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.externalSubject.class", ExternalSubjectHooks.class, false);
498     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.field.class", FieldHooks.class, false);
499     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.group.class", GroupHooks.class, false);
500     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.grouperSession.class", GrouperSessionHooks.class, false);
501     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.groupType.class", GroupTypeHooks.class, false);
502     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.groupTypeTuple.class", GroupTypeTupleHooks.class, false);
503     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.lifecycle.class", LifecycleHooks.class, false);
504     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.loader.class", LoaderHooks.class, false);
505     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.membership.class", MembershipHooks.class, false);
506     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.member.class", MemberHooks.class, false);
507     GrouperConfig.retrieveConfig().assertPropertyValueClass("hooks.stem.class", StemHooks.class, false);
508     
509     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("ddlutils.exclude.subject.tables", true);
510     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("ddlutils.schemaexport.installGrouperData", true);
511     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("ddlutils.failIfNotRightVersion", true);
512     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("ddlutils.dropBackupUuidCols", true);
513     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("ddlutils.dropBackupFieldNameTypeCols", true);
514     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("ddlutils.dropAttributeBackupTableFromGroupUpgrade", true);
515     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("ddlutils.disableComments", true);
516     
517     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("grouperIncludeExclude.use", true);
518     GrouperConfig.retrieveConfig().assertPropertyValueBoolean("grouperIncludeExclude.requireGroups.use", true);
519     
520     Properties properties = GrouperConfig.retrieveConfig().properties();
521     String value = GrouperUtil.propertiesValue(properties, "grouperIncludeExclude.requireGroups.extension.suffix");
522 
523     if (value != null && !value.contains("${i}")) {
524       String error = "Property grouperIncludeExclude.requireGroups.extension.suffix in grouper.properties must contain ${i}";
525       System.err.println("Grouper error: " + error);
526       LOG.error(error);
527     }
528 
529     int i=0;
530     while (true) {
531       String key = "grouperIncludeExclude.requireGroup.attributeOrType." + i;
532       String attributeOrType = GrouperUtil.propertiesValue(properties, key);
533       if (StringUtils.isBlank(attributeOrType)) {
534         break;
535       }
536       if (!StringUtils.equals(attributeOrType, "type") && !StringUtils.equals(attributeOrType, "attribute")) {
537         String error = "Property " + key + " in grouper.properties must be either 'type' or 'attribute'";
538         System.err.println("Grouper error: " + error);
539         LOG.error(error);
540       }
541       i++;
542     }
543   }
544 
545   /** if in check config */
546   public static boolean inCheckConfig = false;
547   
548   /**
549    * check the grouper config safely, log errors
550    */
551   public static void checkConfig() {
552     
553     inCheckConfig = true;
554 
555     try {
556       if (configCheckDisabled()) {
557         return;
558       }
559       
560       //first try to get in the GrouperConfig, just get a property to init stuff
561       GrouperConfig.retrieveConfig().propertyValueString("groups.wheel.group");
562       
563       checkGrouperConfigs();
564       
565       checkConfigProperties();
566       
567       checkGrouperDb();
568       
569       //might as well try to init data at this point...
570       GrouperStartup.initData(false);
571       
572       checkGroups();
573       
574       checkAttributes();
575       
576       postSteps();
577       
578       GrouperSession.internal_callbackRootGrouperSession(new GrouperSessionHandler() {
579       
580         public Object callback(GrouperSession grouperSession) throws GrouperSessionException {
581           //delegate to subject APIconfigs
582           SubjectCheckConfig.checkConfig();
583           return null;
584         }
585       });
586     } finally {
587       inCheckConfig = false;
588     }
589   }
590   
591   public static void checkConfig2() {
592     
593     boolean autoconfigure = GrouperConfig.retrieveConfig().propertyValueBoolean("grouper.attribute.loader.autoconfigure", true);
594     if (!autoconfigure) {
595       return;
596     }
597 
598     final boolean wasInCheckConfig = inCheckConfig;
599 
600     inCheckConfig = true;
601 
602     try {
603       if (configCheckDisabled()) {
604         return;
605       }
606       GrouperSession.internal_callbackRootGrouperSession(new GrouperSessionHandler() {
607         
608         @Override
609         public Object callback(GrouperSession grouperSession) throws GrouperSessionException {
610           {
611             
612             String recentMembershipsRootStemName = GrouperRecentMemberships.recentMembershipsStemName();
613             
614             boolean assignAutoCreate = false;
615             
616             Stem recentMembershipsStem = StemFinder.findByName(grouperSession, recentMembershipsRootStemName, false);
617             if (recentMembershipsStem == null) {
618               recentMembershipsStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
619                 .assignDescription("folder for built in Grouper recent memberships objects").assignName(recentMembershipsRootStemName)
620                 .save();
621             }
622 
623             //see if attributeDef is there
624             String recentMembershipsMarkerDefName = recentMembershipsRootStemName + ":" + GrouperRecentMemberships.GROUPER_RECENT_MEMBERSHIPS_MARKER_DEF;
625             AttributeDef recentMembershipsMarkerDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
626                 recentMembershipsMarkerDefName, false, new QueryOptions().secondLevelCache(false));
627             if (recentMembershipsMarkerDef == null) {
628               recentMembershipsMarkerDef = recentMembershipsStem.addChildAttributeDef(GrouperRecentMemberships.GROUPER_RECENT_MEMBERSHIPS_MARKER_DEF, AttributeDefType.attr);
629               recentMembershipsMarkerDef.setAssignToGroup(true);
630               recentMembershipsMarkerDef.setMultiAssignable(false);
631               recentMembershipsMarkerDef.store();
632               assignAutoCreate = true;
633             }
634             
635             Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(recentMembershipsMarkerDef);
636             
637 
638             //add a name
639             AttributeDefName recentMembershipsMarker = checkAttribute(recentMembershipsStem, recentMembershipsMarkerDef, GrouperRecentMemberships.GROUPER_RECENT_MEMBERSHIPS_MARKER, 
640                 "has recent memberships settings", wasInCheckConfig);
641             
642             //lets add some rule attributes
643             String grouperRecentMembershipsValueDefName = recentMembershipsRootStemName + ":" + GrouperRecentMemberships.GROUPER_RECENT_MEMBERSHIPS_VALUE_DEF;
644             AttributeDef grouperRecentMembershipsValueDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(  
645                 grouperRecentMembershipsValueDefName, false, new QueryOptions().secondLevelCache(false));
646             if (grouperRecentMembershipsValueDef == null) {
647               grouperRecentMembershipsValueDef = recentMembershipsStem.addChildAttributeDef(GrouperRecentMemberships.GROUPER_RECENT_MEMBERSHIPS_VALUE_DEF, AttributeDefType.attr);
648               grouperRecentMembershipsValueDef.setAssignToGroupAssn(true);
649               grouperRecentMembershipsValueDef.setValueType(AttributeDefValueType.string);
650               grouperRecentMembershipsValueDef.store();
651             }
652 
653             Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(grouperRecentMembershipsValueDef);
654 
655             //the attributes can only be assigned to the type def
656             // try an attribute def dependent on an attribute def name
657             grouperRecentMembershipsValueDef.getAttributeDefScopeDelegate().assignOwnerNameEquals(recentMembershipsMarker.getName());
658 
659             //add some names
660             AttributeDefName groupUuidAttributeDefName = checkAttribute(recentMembershipsStem, grouperRecentMembershipsValueDef, GrouperRecentMemberships.GROUPER_RECENT_MEMBERSHIPS_ATTR_GROUP_UUID_FROM, 
661                 "", wasInCheckConfig);
662             AttributeDefName includeEligibleAttributeDefName = checkAttribute(recentMembershipsStem, grouperRecentMembershipsValueDef, GrouperRecentMemberships.GROUPER_RECENT_MEMBERSHIPS_ATTR_INCLUDE_CURRENT,
663                 "true or false if the eligible population should be included in the recent memberships group to reduce provisioning flicker", wasInCheckConfig);
664 
665             //lets add some rule attributes
666             String grouperRecentMembershipsIntValueDefName = recentMembershipsRootStemName + ":" + GrouperRecentMemberships.GROUPER_RECENT_MEMBERSHIPS_INT_VALUE_DEF;
667             AttributeDef grouperRecentMembershipsIntValueDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(  
668                 grouperRecentMembershipsIntValueDefName, false, new QueryOptions().secondLevelCache(false));
669             if (grouperRecentMembershipsIntValueDef == null) {
670               grouperRecentMembershipsIntValueDef = recentMembershipsStem.addChildAttributeDef(GrouperRecentMemberships.GROUPER_RECENT_MEMBERSHIPS_INT_VALUE_DEF, AttributeDefType.attr);
671               grouperRecentMembershipsIntValueDef.setAssignToGroupAssn(true);
672               grouperRecentMembershipsIntValueDef.setValueType(AttributeDefValueType.integer);
673               grouperRecentMembershipsIntValueDef.store();
674             }
675 
676             //the attributes can only be assigned to the type def
677             // try an attribute def dependent on an attribute def name
678             grouperRecentMembershipsIntValueDef.getAttributeDefScopeDelegate().assignOwnerNameEquals(recentMembershipsMarker.getName());
679 
680             Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(grouperRecentMembershipsIntValueDef);
681 
682             AttributeDefName microsAttributeDefName = checkAttribute(recentMembershipsStem, grouperRecentMembershipsIntValueDef, GrouperRecentMemberships.GROUPER_RECENT_MEMBERSHIPS_ATTR_MICROS, 
683                 "Number of micros that the recent memberships last", wasInCheckConfig);
684 
685             
686             String groupName = recentMembershipsRootStemName + ":" + GrouperRecentMemberships.GROUPER_RECENT_MEMBERSHIPS_LOADER_GROUP_NAME;
687             Group group = GrouperDAOFactory.getFactory().getGroup().findByNameSecure(
688                 groupName, false, new QueryOptions().secondLevelCache(false), GrouperUtil.toSet(TypeOfGroup.group));
689             
690             String descriptionIfEnabled = "Holds the loader configuration of the recent memberships job that populates the recent memberships groups configured by attributes.  This is enabled in grouper.properties";
691             String descriptionIfDisabled = "Holds the loader configuration of the recent memberships job that populates the recent memberships groups configured by attributes.  This is not enabled in grouper.properties";
692 
693             boolean recentMembershipsEnabled = GrouperConfig.retrieveConfig().propertyValueBoolean("grouper.recentMemberships.loaderJob.enable", true);
694             String descriptionShouldBe = recentMembershipsEnabled ? descriptionIfEnabled : descriptionIfDisabled;
695 
696             Boolean changeLoader = null;
697 
698             if (group != null) {
699               changeLoader = !StringUtils.equals(descriptionShouldBe, group.getDescription());
700             }
701             
702             if (group == null) {
703               changeLoader = (changeLoader != null && changeLoader) || recentMembershipsEnabled;
704             }
705             
706             if (group == null) {
707               group = new GroupSave(grouperSession).assignName(groupName)
708                 .assignDescription(descriptionShouldBe).save();
709             }
710             
711             // if its new or the state has changed
712             if (changeLoader != null && changeLoader) {
713               GrouperRecentMemberships.setupRecentMembershipsLoaderJob(group);
714             }
715             
716             // these attribute tell a grouper rule to auto assign the three name value pair attributes to the assignment when the marker is assigned
717             if (assignAutoCreate) {
718               AttributeDefName autoCreateMarker = AttributeDefNameFinder.findByName(AttributeAutoCreateHook.attributeAutoCreateStemName() + ":" + AttributeAutoCreateHook.GROUPER_ATTRIBUTE_AUTO_CREATE_MARKER, true);
719               AttributeDefName ifName = AttributeDefNameFinder.findByName(AttributeAutoCreateHook.attributeAutoCreateStemName() + ":" + AttributeAutoCreateHook.GROUPER_ATTRIBUTE_AUTO_CREATE_ATTR_IF_NAME, true);
720               AttributeDefName thenNames = AttributeDefNameFinder.findByName(AttributeAutoCreateHook.attributeAutoCreateStemName() + ":" + AttributeAutoCreateHook.GROUPER_ATTRIBUTE_AUTO_CREATE_ATTR_THEN_NAMES_ON_ASSIGN, true);
721               
722               AttributeAssignResult attributeAssignResult = recentMembershipsMarkerDef.getAttributeDelegate().assignAttribute(autoCreateMarker);
723               attributeAssignResult.getAttributeAssign().getAttributeValueDelegate().assignValue(ifName.getName(), recentMembershipsMarker.getName());
724               attributeAssignResult.getAttributeAssign().getAttributeValueDelegate().assignValue(thenNames.getName(), microsAttributeDefName.getName() 
725                   + ", " + groupUuidAttributeDefName.getName() + ", " + includeEligibleAttributeDefName.getName());
726             }
727             
728           }
729           return null;
730         }
731       });
732       
733     } finally {
734       inCheckConfig = false;
735     }
736 
737   }
738   
739   /**
740    * 
741    */
742   public static void postSteps() {
743 
744     boolean theTesting = false;
745     long now = System.currentTimeMillis();
746     try {
747       String grouperTestClassName = "edu.internet2.middleware.grouper.helper.GrouperTest";
748       Class grouperTestClass = GrouperUtil.forName(grouperTestClassName);
749       theTesting = (Boolean)GrouperUtil.callMethod(grouperTestClass, "isTesting");
750     } catch (Exception e) {
751       //ignore
752       LOG.debug("Likely non-fatal error seeing if testing, took (ms): " + (System.currentTimeMillis() - now), e);
753     }
754     final boolean testing = theTesting;
755     
756     // do this in a thread so we dont delay startup
757     Thread thread = new Thread(new Runnable() {
758 
759       public void run() {
760         
761         doneWithExtraConfig = false;
762         try {
763 
764           for (int i=0;i<200;i++) {
765             if (GrouperStartup.isFinishedStartupSuccessfully()) {
766               break;
767             }
768             //wait a sec for other things to get all initted
769             GrouperUtil.sleep(100);
770           }
771           if (!testing) {
772             //wait a sec for other things to get all initted
773             GrouperUtil.sleep(5000);
774           }
775           
776           GrouperContext grouperContext = GrouperContext.retrieveDefaultContext();
777           if (grouperContext != null && grouperContext.getGrouperEngine() == GrouperEngineBuiltin.JUNIT) {
778             return;
779           }
780           
781           if (GrouperConfig.retrieveConfig().propertyValueBoolean("grouperDeprovisioningCheckSettingsOnDeprovisionedGroups", true)) {
782           
783             try {
784               GrouperSession grouperSession = GrouperSession.startRootSession();
785               
786               // group that users who are allowed to deprovision other users are in
787               for (String affiliation : GrouperDeprovisioningAffiliation.retrieveDeprovisioningAffiliations()) {
788 
789                 // group that deprovisioned users go in (temporarily, but history will always be there)
790                 String deprovisioningGroupWhichHasBeenDeprovisionedName = GrouperDeprovisioningJob.retrieveGroupNameWhichHasBeenDeprovisioned(affiliation);
791                 
792                 Group group = GroupFinder.findByName(grouperSession, deprovisioningGroupWhichHasBeenDeprovisionedName, false);
793                 if (group != null) {
794                   GrouperDeprovisioningOverallConfiguration grouperDeprovisioningOverallConfiguration = GrouperDeprovisioningOverallConfiguration.retrieveConfiguration(group, false);
795                   
796                   // group that users who are allowed to deprovision other users are in
797                   for (String affiliationToConfigure : GrouperDeprovisioningAffiliation.retrieveDeprovisioningAffiliations()) {
798                     
799                     GrouperDeprovisioningConfiguration grouperDeprovisioningConfiguration = grouperDeprovisioningOverallConfiguration.getAffiliationToConfiguration().get(affiliationToConfigure);
800                     
801                     GrouperDeprovisioningAttributeValue grouperDeprovisioningAttributeValue = grouperDeprovisioningConfiguration.getNewConfig();
802                     
803                     boolean hasChange = false;
804                     // if theres no configuration, or if the configuration is inherited, then clear it out
805                     if (grouperDeprovisioningAttributeValue == null) {
806                       grouperDeprovisioningAttributeValue = new GrouperDeprovisioningAttributeValue();
807                       grouperDeprovisioningAttributeValue.setAffiliationString(affiliationToConfigure);
808                       grouperDeprovisioningAttributeValue.setGrouperDeprovisioningConfiguration(grouperDeprovisioningConfiguration);
809                       grouperDeprovisioningConfiguration.setNewConfig(grouperDeprovisioningAttributeValue);
810                       hasChange = true;
811                     }
812                     if (StringUtils.isBlank(grouperDeprovisioningAttributeValue.getDirectAssignmentString()) || !grouperDeprovisioningAttributeValue.isDirectAssignment()) {
813                       grouperDeprovisioningAttributeValue.setDirectAssignment(true);
814                       hasChange = true;
815                     }
816                     
817                     if (StringUtils.isBlank(grouperDeprovisioningAttributeValue.getDeprovisionString()) || grouperDeprovisioningAttributeValue.isDeprovision()) {
818                       grouperDeprovisioningAttributeValue.setDeprovision(false);
819                       hasChange = true;
820                     }
821                     
822                     if (StringUtils.isBlank(grouperDeprovisioningAttributeValue.getAutoselectForRemovalString()) || grouperDeprovisioningAttributeValue.isAutoselectForRemoval()) {
823                       grouperDeprovisioningAttributeValue.setAutoselectForRemoval(false);
824                       hasChange = true;
825                     }
826                     
827                     if (StringUtils.isBlank(grouperDeprovisioningAttributeValue.getAutoChangeLoaderString()) || grouperDeprovisioningAttributeValue.isAutoChangeLoader()) {
828                       grouperDeprovisioningAttributeValue.setAutoChangeLoader(false);
829                       hasChange = true;
830                     }
831                     
832                     if (StringUtils.isBlank(grouperDeprovisioningAttributeValue.getShowForRemovalString()) || grouperDeprovisioningAttributeValue.isShowForRemoval()) {
833                       grouperDeprovisioningAttributeValue.setShowForRemoval(false);
834                       hasChange = true;
835                     }
836                     
837                     if (hasChange) {
838                       grouperDeprovisioningConfiguration.storeConfiguration();
839                     }
840                   }
841                   
842                 }
843               }
844                 
845             } catch (RuntimeException re) {
846               //log incase thread didnt finish when screen was drawing
847               LOG.error("Error with additional config", re);
848             }
849           }
850         } finally {
851           doneWithExtraConfig = true;
852         }
853       }
854     });
855 
856     thread.setDaemon(true);
857     thread.start();
858     if (testing) {
859       GrouperUtil.threadJoin(thread);
860     }
861 
862   }
863 
864   /**
865    * make sure configured groups are there 
866    */
867   public static void checkGroups() {
868     
869     boolean wasInCheckConfig = inCheckConfig;
870     if (!wasInCheckConfig) {
871       inCheckConfig = true;
872     }
873     
874     //groups auto-create
875     //#configuration.autocreate.group.name.0 = etc:uiUsers
876     //#configuration.autocreate.group.description.0 = users allowed to log in to the UI
877     //#configuration.autocreate.group.subjects.0 = johnsmith
878     int i=0;
879     
880     GrouperSession grouperSession = null;
881     boolean startedGrouperSession = false;
882     try {
883       grouperSession = GrouperSession.staticGrouperSession(false);
884 
885       if (grouperSession == null) {
886         grouperSession = GrouperSession.startRootSession();
887         startedGrouperSession = true;
888       }
889       
890       while(true) {
891         String groupName = null;
892         try {
893           String groupNameKey = "configuration.autocreate.group.name." + i;
894           groupName = GrouperConfig.retrieveConfig().propertyValueString(groupNameKey);
895           
896           if (StringUtils.isBlank(groupName)) {
897             break;
898           }
899           
900           String groupDescription = GrouperConfig.retrieveConfig().propertyValueString("configuration.autocreate.group.description." + i);
901           String subjectsKey = "configuration.autocreate.group.subjects." + i;
902           String subjects = GrouperConfig.retrieveConfig().propertyValueString(subjectsKey);
903     
904           Groupuper/Group.html#Group">Group[] theGroup = new Group[1];
905           //first the group
906           checkGroup(grouperSession, groupName, wasInCheckConfig, true, wasInCheckConfig, null, groupDescription, "grouper.properties key " + groupNameKey, theGroup);
907           //now the subjects
908           if (!StringUtils.isBlank(subjects)) {
909             String[] subjectArray = GrouperUtil.splitTrim(subjects, ",");
910             for (String subjectId : subjectArray) {
911               
912               try {
913                 Subject subject = SubjectFinder.findByIdOrIdentifier(subjectId, false);
914                 boolean added = theGroup[0].addMember(subject, false);
915                 if (added && wasInCheckConfig) {
916                   String error = "auto-added subject " + subjectId + " to group: " + theGroup[0].getName();
917                   System.err.println("Grouper warning: " + error);
918                   LOG.warn(error);
919                 }
920               } catch (MemberAddException mae) {
921                 throw new RuntimeException("this should never happen", mae);
922               } catch (InsufficientPrivilegeException snfe) {
923                 throw new RuntimeException("this should never happen", snfe);
924               } catch (SubjectNotFoundException snfe) {
925                 throw new RuntimeException("this should never happen", snfe);
926               } catch (SubjectNotUniqueException snue) {
927                 String error = "subject not unique from grouper.properties key: " + subjectsKey + ", " + subjectId;
928                 System.err.println("Grouper error: " + error);
929                 LOG.error(error, snue);
930               }
931             }
932               
933           }
934         } catch (RuntimeException re) {
935           GrouperUtil.injectInException(re, ", problem with auto-create group: " + groupName);
936         }
937         i++;
938       }
939       {
940         boolean useWheel = GrouperConfig.retrieveConfig().propertyValueBoolean("groups.wheel.use", false);
941         if (useWheel) {
942           String wheelName = GrouperConfig.retrieveConfig().propertyValueString("groups.wheel.group");
943           if (StringUtils.isBlank(wheelName) && wasInCheckConfig) {
944             String error = "grouper.properties property groups.wheel.group should not be blank if groups.wheel.use is true";
945             System.err.println("Grouper error: " + error);
946             LOG.warn(error);
947           } else {
948             checkGroup(grouperSession, wheelName, wasInCheckConfig, null, wasInCheckConfig, null, "system administrators with all privileges", 
949                 "wheel group from grouper.properties key: groups.wheel.group", null);
950           }
951         }
952       }      
953       {
954         boolean useViewonlyWheel = GrouperConfig.retrieveConfig().propertyValueBoolean("groups.wheel.viewonly.use", false);
955         if (useViewonlyWheel) {
956           String wheelViewonlyName = GrouperConfig.retrieveConfig().propertyValueString("groups.wheel.viewonly.group");
957           if (StringUtils.isBlank(wheelViewonlyName) && wasInCheckConfig) {
958             String error = "grouper.properties property groups.wheel.viewonly.group should not be blank if groups.wheel.viewonly.use is true";
959             System.err.println("Grouper error: " + error);
960             LOG.warn(error);
961           } else {
962             checkGroup(grouperSession, wheelViewonlyName, wasInCheckConfig, null, wasInCheckConfig, null, "system administrators with view privileges", 
963                 "viewonly wheel group from grouper.properties key: groups.wheel.viewonly.group", null);
964           }
965         }
966       }      
967       {
968         boolean useReadonlyWheel = GrouperConfig.retrieveConfig().propertyValueBoolean("groups.wheel.readonly.use", false);
969         if (useReadonlyWheel) {
970           String wheelReadonlyName = GrouperConfig.retrieveConfig().propertyValueString("groups.wheel.readonly.group");
971           if (StringUtils.isBlank(wheelReadonlyName) && wasInCheckConfig) {
972             String error = "grouper.properties property groups.wheel.readonly.group should not be blank if groups.wheel.readonly.use is true";
973             System.err.println("Grouper error: " + error);
974             LOG.warn(error);
975           } else {
976             checkGroup(grouperSession, wheelReadonlyName, wasInCheckConfig, null, wasInCheckConfig, null, "system administrators with read privileges", 
977                 "readonly wheel group from grouper.properties key: groups.wheel.readonly.group", null);
978           }
979         }
980       }      
981       // security.stem.groupAllowedToMoveStem
982       String allowedGroupName = "security.stem.groupAllowedToMoveStem";
983       String groupAllowedToMoveStem = GrouperConfig.retrieveConfig().propertyValueString(allowedGroupName);
984       if (StringUtils.isNotBlank(groupAllowedToMoveStem)) {
985         checkGroup(grouperSession, groupAllowedToMoveStem, wasInCheckConfig, null, wasInCheckConfig, null, 
986             null, "grouper.properties key: " + allowedGroupName, null);        
987       }
988       
989       // security.stem.groupAllowedToRenameStem
990       allowedGroupName = "security.stem.groupAllowedToRenameStem";
991       String groupAllowedToRenameStem = GrouperConfig.retrieveConfig().propertyValueString(allowedGroupName);
992       if (StringUtils.isNotBlank(groupAllowedToRenameStem)) {
993         checkGroup(grouperSession, groupAllowedToRenameStem, wasInCheckConfig, null, wasInCheckConfig, null, 
994             null, "grouper.properties key: " + allowedGroupName, null);        
995       }
996       
997       // security.stem.groupAllowedToCopyStem
998       allowedGroupName = "security.stem.groupAllowedToCopyStem";
999       String groupAllowedToCopyStem = GrouperConfig.retrieveConfig().propertyValueString(allowedGroupName);
1000       if (StringUtils.isNotBlank(groupAllowedToCopyStem)) {
1001         checkGroup(grouperSession, groupAllowedToCopyStem, wasInCheckConfig, null, wasInCheckConfig, null, 
1002             null, "grouper.properties key: " + allowedGroupName, null);        
1003       }
1004       
1005       //groups in requireGroups
1006       i=0;
1007       while(true) {
1008         String groupName = GrouperConfig.retrieveConfig().propertyValueString("grouperIncludeExclude.requireGroup.group." + i);
1009         
1010         if (StringUtils.isBlank(groupName)) {
1011           break;
1012         }
1013         
1014         String key = "grouperIncludeExclude.requireGroup.description." + i;
1015         String description = GrouperConfig.retrieveConfig().propertyValueString(key);
1016         
1017         checkGroup(grouperSession, groupName, wasInCheckConfig, null, wasInCheckConfig, null, description, 
1018           "requireGroup from grouper.properties key: " + key, null);
1019         
1020         i++;
1021       }
1022       
1023       //groups that manage types
1024       Map<String, String> typePatterns = typeSecuritySettings();
1025       for (String key: typePatterns.keySet()) {
1026         
1027         Matcher matcher = typeSecurityPattern.matcher(key);
1028         
1029         matcher.matches();
1030         String typeName = matcher.group(1);
1031         String settingType = matcher.group(2);
1032         if (!StringUtils.equalsIgnoreCase("allowOnlyGroup", settingType)) {
1033           continue;
1034         }
1035         //this is a group
1036         String groupName = typePatterns.get(key);
1037         String description = "Group whose members are allowed to edit type (and related attributes): " + typeName;
1038         checkGroup(grouperSession, groupName, wasInCheckConfig, null, wasInCheckConfig, null, description, 
1039             "type security from grouper.properties key: " + key, null);
1040         
1041       }
1042       
1043       //groups that manage access to sort and search strings
1044       Map<String, String> memberSortSearchPatterns = memberSortSearchSecuritySettings();
1045       for (String key: memberSortSearchPatterns.keySet()) {
1046         
1047         Matcher matcher = memberSortSearchSecurityPattern.matcher(key);
1048         
1049         matcher.matches();
1050         String name = matcher.group(1) + matcher.group(2);
1051         String settingType = matcher.group(3);
1052         if (!StringUtils.equalsIgnoreCase("allowOnlyGroup", settingType)) {
1053           continue;
1054         }
1055         //this is a group
1056         String groupName = memberSortSearchPatterns.get(key);
1057         String description = "Group whose members are allowed to access: " + name;
1058         checkGroup(grouperSession, groupName, wasInCheckConfig, null, wasInCheckConfig, null, description, 
1059             "member sort/search security from grouper.properties key: " + key, null);
1060         
1061       }
1062       
1063       if (MembershipCannotAddSelfToGroupHook.cannotAddSelfEnabled()){
1064         String cannotAddSelfRootStemName = MembershipCannotAddSelfToGroupHook.cannotAddSelfStemName();
1065         
1066         Stem cannotAddSelfRootStem = StemFinder.findByName(grouperSession, cannotAddSelfRootStemName, false);
1067         if (cannotAddSelfRootStem == null) {
1068           cannotAddSelfRootStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
1069             .assignDescription("folder for objects related to cannot add self to group").assignName(cannotAddSelfRootStemName)
1070             .save();
1071         }
1072 
1073         {
1074           // users who can assign "cannot add self as member of group"
1075           String cannotAddSelfAssignGroupName = MembershipCannotAddSelfToGroupHook.cannotAddSelfAssignGroupName();
1076 
1077           checkGroup(grouperSession, cannotAddSelfAssignGroupName, wasInCheckConfig, true, 
1078               wasInCheckConfig, null, 
1079               "users who can assign \"cannot add self as member of group\"", 
1080               "users who can assign \"cannot add self as member of group\"",
1081               null);
1082         }        
1083         
1084         {
1085           // users who can revoke "cannot add self as member of group"
1086           String cannotAddSelfRevokeGroupName = MembershipCannotAddSelfToGroupHook.cannotAddSelfRevokeGroupName();
1087 
1088           checkGroup(grouperSession, cannotAddSelfRevokeGroupName, wasInCheckConfig, true, 
1089               wasInCheckConfig, null, 
1090               "users who can revoke \"cannot add self as member of group\"", 
1091               "users who can revoke \"cannot add self as member of group\"",
1092               null);
1093         }        
1094         
1095         //see if attributeDef is there
1096         String cannotAddSelfTypeDefName = MembershipCannotAddSelfToGroupHook.cannotAddSelfNameOfAttributeDef();
1097         AttributeDef cannotAddSelfType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
1098             cannotAddSelfTypeDefName, false, new QueryOptions().secondLevelCache(false));
1099         if (cannotAddSelfType == null) {
1100           cannotAddSelfType = cannotAddSelfRootStem.addChildAttributeDef(GrouperUtil.extensionFromName(cannotAddSelfTypeDefName), AttributeDefType.type);
1101           //assign once
1102           cannotAddSelfType.setMultiAssignable(false);
1103           cannotAddSelfType.setAssignToGroup(true);
1104           cannotAddSelfType.store();
1105         }
1106         
1107         //add a name
1108         checkAttribute(cannotAddSelfRootStem, cannotAddSelfType, GrouperUtil.extensionFromName(MembershipCannotAddSelfToGroupHook.cannotAddSelfNameOfAttributeDefName()), 
1109             "Assign this attribute to a group and users will not be able to add themself to the group for separation of duties", wasInCheckConfig);
1110         
1111         MembershipCannotAddSelfToGroupHook.registerHookIfNecessary();
1112       }
1113       
1114       //if (GrouperDeprovisioningSettings.deprovisioningEnabled()) {
1115       // always add these objects
1116       {
1117         String deprovisioningRootStemName = GrouperDeprovisioningSettings.deprovisioningStemName();
1118         
1119         Stem deprovisioningStem = StemFinder.findByName(grouperSession, deprovisioningRootStemName, false);
1120         if (deprovisioningStem == null) {
1121           deprovisioningStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
1122             .assignDescription("folder for built in Grouper deprovisioning objects").assignName(deprovisioningRootStemName)
1123             .save();
1124         }
1125 
1126         boolean autocreate = GrouperConfig.retrieveConfig().propertyValueBoolean("deprovisioning.autocreate.groups", true);
1127         
1128         {
1129           // # users in this group who are admins of an affiliation but who are not Grouper SysAdmins, will be 
1130           // # able to deprovision from all grouper groups/objects, not just groups they have access to UPDATE/ADMIN
1131           // deprovisioning.admin.group = $$deprovisioning.systemFolder$$:deprovisioningAdmins
1132           String deprovisioningAdminGroupName = GrouperDeprovisioningSettings.retrieveDeprovisioningAdminGroupName();
1133 
1134           checkGroup(grouperSession, deprovisioningAdminGroupName, wasInCheckConfig, autocreate, 
1135               wasInCheckConfig, null, 
1136               "deprovisioning admin group can deprovision from all groups/objects in Grouper even if the user is not a Grouper overall SysAdmin", 
1137               "deprovisioning admin group can deprovision from all groups/objects in Grouper even if the user is not a Grouper overall SysAdmin",
1138               null);
1139         }        
1140         
1141         // group that users who are allowed to deprovision other users are in
1142         for (String affiliation : GrouperDeprovisioningAffiliation.retrieveDeprovisioningAffiliations()) {
1143 
1144           String deprovisioningManagersMustBeInGroupName = GrouperDeprovisioningJob.retrieveDeprovisioningManagersMustBeInGroupName(affiliation);
1145 
1146           checkGroup(grouperSession, deprovisioningManagersMustBeInGroupName, wasInCheckConfig, autocreate, 
1147               wasInCheckConfig, null, "deprovisioning: " + affiliation + ", group that users who are allowed to deprovision other users are in", 
1148               "deprovisioning: " + affiliation + ", group that users who are allowed to deprovision other users are in", null);
1149 
1150           // group that deprovisioned users go in (temporarily, but history will always be there)
1151           String deprovisioningGroupWhichHasBeenDeprovisionedName = GrouperDeprovisioningJob.retrieveGroupNameWhichHasBeenDeprovisioned(affiliation);
1152           
1153           checkGroup(grouperSession, deprovisioningGroupWhichHasBeenDeprovisionedName, wasInCheckConfig, autocreate, 
1154               wasInCheckConfig, null, "deprovisioning: " + affiliation + ", group that deprovisioned users go in (temporarily, but history will always be there)", 
1155               "deprovisioning: " + affiliation + ", group that deprovisioned users go in (temporarily, but history will always be there)", null);
1156 
1157           
1158         }
1159         
1160         //see if attributeDef is there
1161         String deprovisioningTypeDefName = deprovisioningRootStemName + ":" + GrouperDeprovisioningAttributeNames.DEPROVISIONING_DEF;
1162         AttributeDef deprovisioningType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
1163             deprovisioningTypeDefName, false, new QueryOptions().secondLevelCache(false));
1164         if (deprovisioningType == null) {
1165           deprovisioningType = deprovisioningStem.addChildAttributeDef(GrouperDeprovisioningAttributeNames.DEPROVISIONING_DEF, AttributeDefType.type);
1166           //assign once for each affiliation
1167           deprovisioningType.setMultiAssignable(true);
1168           deprovisioningType.setAssignToGroup(true);
1169           deprovisioningType.setAssignToAttributeDef(true);
1170           deprovisioningType.setAssignToStem(true);
1171           deprovisioningType.store();
1172         }
1173         
1174         //add a name
1175         AttributeDefName attribute = checkAttribute(deprovisioningStem, deprovisioningType, GrouperDeprovisioningAttributeNames.DEPROVISIONING_BASE, "has deprovisioning attributes", wasInCheckConfig);
1176         
1177         //lets add some rule attributes
1178         String deprovisioningAttrDefName = deprovisioningRootStemName + ":" + GrouperDeprovisioningAttributeNames.DEPROVISIONING_VALUE_DEF;
1179         AttributeDef deprovisioningAttrType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(  
1180             deprovisioningAttrDefName, false, new QueryOptions().secondLevelCache(false));
1181         if (deprovisioningAttrType == null) {
1182           deprovisioningAttrType = deprovisioningStem.addChildAttributeDef(GrouperDeprovisioningAttributeNames.DEPROVISIONING_VALUE_DEF, AttributeDefType.attr);
1183           deprovisioningAttrType.setAssignToGroupAssn(true);
1184           deprovisioningAttrType.setAssignToStemAssn(true);
1185           deprovisioningAttrType.setAssignToAttributeDefAssn(true);
1186           deprovisioningAttrType.setValueType(AttributeDefValueType.string);
1187           deprovisioningAttrType.store();
1188         }
1189 
1190         //the attributes can only be assigned to the type def
1191         // try an attribute def dependent on an attribute def name
1192         deprovisioningAttrType.getAttributeDefScopeDelegate().assignOwnerNameEquals(attribute.getName());
1193         
1194         checkAttribute(deprovisioningStem, deprovisioningAttrType, GrouperDeprovisioningAttributeNames.DEPROVISIONING_INHERITED_FROM_FOLDER_ID,
1195             "Stem ID of the folder where the configuration is inherited from.  This is blank if this is a direct assignment and not inherited", wasInCheckConfig);
1196         checkAttribute(deprovisioningStem, deprovisioningAttrType, GrouperDeprovisioningAttributeNames.DEPROVISIONING_AFFILIATION, 
1197             "Affiliation configured in the grouper.properties.  e.g. employee, student, etc", wasInCheckConfig);
1198         checkAttribute(deprovisioningStem, deprovisioningAttrType, GrouperDeprovisioningAttributeNames.DEPROVISIONING_ALLOW_ADDS_WHILE_DEPROVISIONED, 
1199             "If allows adds to group of people who are deprovisioned.  can be: blank, true, or false.  "
1200             + "If blank, then will not allow adds unless auto change loader is false", wasInCheckConfig);
1201         checkAttribute(deprovisioningStem, deprovisioningAttrType, GrouperDeprovisioningAttributeNames.DEPROVISIONING_AUTO_CHANGE_LOADER, 
1202             "If this is a loader job, if being in a deprovisioned group means the user "
1203             + "should not be in the loaded group. can be: blank (true), or false (false)", wasInCheckConfig);
1204         checkAttribute(deprovisioningStem, deprovisioningAttrType, GrouperDeprovisioningAttributeNames.DEPROVISIONING_AUTOSELECT_FOR_REMOVAL, 
1205             "If the deprovisioning screen should autoselect this object as an object to deprovision can be: blank, true, or false.  "
1206             + "If blank, then will autoselect unless deprovisioningAutoChangeLoader is false", wasInCheckConfig);
1207         checkAttribute(deprovisioningStem, deprovisioningAttrType, GrouperDeprovisioningAttributeNames.DEPROVISIONING_DIRECT_ASSIGNMENT, 
1208             "if deprovisioning configuration is directly assigned to the group or folder or inherited from parent", wasInCheckConfig);
1209         checkAttribute(deprovisioningStem, deprovisioningAttrType, GrouperDeprovisioningAttributeNames.DEPROVISIONING_EMAIL_ADDRESSES, 
1210             "Email addresses to send deprovisioning messages.  If blank, then send to group managers, or comma separated email addresses (mutually exclusive with deprovisioningMailToGroup)", wasInCheckConfig);
1211         checkAttribute(deprovisioningStem, deprovisioningAttrType, GrouperDeprovisioningAttributeNames.DEPROVISIONING_MAIL_TO_GROUP, 
1212             "Group ID which holds people to email members of that group to send deprovisioning messages (mutually exclusive with deprovisioningEmailAddresses)", wasInCheckConfig);
1213         checkAttribute(deprovisioningStem, deprovisioningAttrType, GrouperDeprovisioningAttributeNames.DEPROVISIONING_SEND_EMAIL, 
1214             "If this is true, then send an email about the deprovisioning event.  If the assignments were removed, then give a "
1215             + "description of the action.  If assignments were not removed, then remind the managers to unassign.  Can be <blank>, true, or false.  "
1216             + "Defaults to false unless the assignments were not removed.", wasInCheckConfig);
1217         checkAttribute(deprovisioningStem, deprovisioningAttrType, GrouperDeprovisioningAttributeNames.DEPROVISIONING_SHOW_FOR_REMOVAL, 
1218             "If the deprovisioning screen should show this object if the user as an assignment.  "
1219             + "Can be: blank, true, or false.  If blank, will default to true unless auto change loader is false.", wasInCheckConfig);
1220         checkAttribute(deprovisioningStem, deprovisioningAttrType, GrouperDeprovisioningAttributeNames.DEPROVISIONING_DEPROVISION, 
1221             "if this object should be in consideration for the deprovisioning system.  Can be: blank, true, or false.  Defaults to true", wasInCheckConfig);
1222         checkAttribute(deprovisioningStem, deprovisioningAttrType, GrouperDeprovisioningAttributeNames.DEPROVISIONING_STEM_SCOPE,
1223             "If configuration is assigned to a folder, then this is 'one' or 'sub'.  'one' means only applicable to objects"
1224             + " directly in this folder.  'sub' (default) means applicable to all objects in this folder and "
1225             + "subfolders.  Note, the inheritance stops when a sub folder or object has configuration assigned.", wasInCheckConfig);
1226         checkAttribute(deprovisioningStem, deprovisioningAttrType, GrouperDeprovisioningAttributeNames.DEPROVISIONING_EMAIL_BODY, 
1227             "custom email body for emails, if blank use the default configured body.  "
1228             + "Note there are template variables $$name$$ $$netId$$ $$userSubjectId$$ $$userEmailAddress$$ $$userDescription$$", wasInCheckConfig);
1229         checkAttribute(deprovisioningStem, deprovisioningAttrType, GrouperDeprovisioningAttributeNames.DEPROVISIONING_LAST_EMAILED_DATE, 
1230             "yyyy/mm/dd date that this was last emailed so multiple emails dont go out on same day", wasInCheckConfig);
1231         checkAttribute(deprovisioningStem, deprovisioningAttrType, GrouperDeprovisioningAttributeNames.DEPROVISIONING_CERTIFIED_MILLIS, 
1232             "(String) number of millis since 1970 that this group was certified for deprovisioning. i.e. the group managers"
1233             + " indicate that the deprovisioned users are ok being in the group and do not send email reminders about it" 
1234             + " anymore until there are newly deprovisioned entities", wasInCheckConfig);
1235 
1236       }
1237       
1238       {
1239         // add workflow admin group
1240         String workflowEditorsGroup = GrouperWorkflowSettings.workflowEditorsGroup();
1241 
1242         checkGroup(grouperSession, workflowEditorsGroup, wasInCheckConfig, true, 
1243             wasInCheckConfig, null,
1244             "Workflow editors group",
1245             "Workflow editors group",
1246             null);
1247       }
1248       
1249       {
1250         // loader viewers
1251         String loaderViewers = GrouperUiConfigInApi.retrieveConfig().propertyValueString("uiV2.loader.must.be.in.group", GrouperConfig.retrieveConfig().propertyValueString("grouper.rootStemForBuiltinObjects") + ":loaderViewers");
1252 
1253         checkGroup(grouperSession, loaderViewers, wasInCheckConfig, true, 
1254             wasInCheckConfig, null,
1255             "Loader viewers",
1256             "Group contains people who can see the overall loader screen in Misc, and if they have VIEW on a group they can see the loader tab and functions",
1257             null);
1258       }
1259       
1260       {
1261         // loader editors
1262         String loaderEditors = GrouperUiConfigInApi.retrieveConfig().propertyValueString("uiV2.loader.edit.if.in.group", GrouperConfig.retrieveConfig().propertyValueString("grouper.rootStemForBuiltinObjects") + ":loaderEditors");
1263 
1264         checkGroup(grouperSession, loaderEditors, wasInCheckConfig, true, 
1265             wasInCheckConfig, null,
1266             "Loader editors",
1267             "Group contains people who can see the overall loader screen in Misc, and if they have VIEW on a group they can see and edit the loader tab and settings",
1268             null);
1269       }
1270       
1271       // add attribute defs for provisioning 
1272       // (https://spaces.at.internet2.edu/display/Grouper/Grouper+provisioning+in+UI)
1273       {
1274         String grouperProvisioningUiRootStemName = GrouperProvisioningSettings.provisioningConfigStemName();
1275         
1276         Stem grouperProvisioningStemName = StemFinder.findByName(grouperSession, grouperProvisioningUiRootStemName, false);
1277         if (grouperProvisioningStemName == null) {
1278           grouperProvisioningStemName = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
1279             .assignDescription("folder to store attribute defs and names for provisioning in ui").assignName(grouperProvisioningUiRootStemName)
1280             .save();
1281         }
1282 
1283         //see if attributeDef is there
1284         String provisioningDefName = grouperProvisioningUiRootStemName + ":" + GrouperProvisioningAttributeNames.PROVISIONING_DEF;
1285         AttributeDef provisioningDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
1286             provisioningDefName, false, new QueryOptions().secondLevelCache(false));
1287         if (provisioningDef == null) {
1288           provisioningDef = grouperProvisioningStemName.addChildAttributeDef(GrouperProvisioningAttributeNames.PROVISIONING_DEF, AttributeDefType.type);
1289           //assign once for each target
1290           provisioningDef.setMultiAssignable(true);
1291           provisioningDef.setAssignToGroup(true);
1292           provisioningDef.setAssignToMember(true);
1293           provisioningDef.setAssignToEffMembership(true);
1294           provisioningDef.setAssignToStem(true);
1295           
1296           provisioningDef.store();
1297         }
1298         
1299         if (provisioningDef.isAssignToEffMembership() == false) {
1300           provisioningDef.setAssignToEffMembership(true);
1301           provisioningDef.setAssignToMember(true);
1302           
1303           provisioningDef.store();
1304         }
1305         
1306         
1307         //add a name
1308         AttributeDefName attribute = checkAttribute(grouperProvisioningStemName, provisioningDef, GrouperProvisioningAttributeNames.PROVISIONING_ATTRIBUTE_NAME, "has provisioning attributes", wasInCheckConfig);
1309         
1310         //lets add some rule attributes
1311         String provisioningValueAttrDefName = grouperProvisioningUiRootStemName + ":" + GrouperProvisioningAttributeNames.PROVISIONING_VALUE_DEF;
1312         AttributeDef provisioningAttrValueDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(  
1313             provisioningValueAttrDefName, false, new QueryOptions().secondLevelCache(false));
1314         if (provisioningAttrValueDef == null) {
1315           provisioningAttrValueDef = grouperProvisioningStemName.addChildAttributeDef(GrouperProvisioningAttributeNames.PROVISIONING_VALUE_DEF, AttributeDefType.attr);
1316           
1317           provisioningAttrValueDef.setAssignToGroupAssn(true);
1318           provisioningAttrValueDef.setAssignToStemAssn(true);
1319           provisioningAttrValueDef.setAssignToMemberAssn(true);
1320           provisioningAttrValueDef.setAssignToEffMembershipAssn(true);
1321           provisioningAttrValueDef.setAssignToAttributeDefAssn(true);
1322           provisioningAttrValueDef.setValueType(AttributeDefValueType.string);
1323           provisioningAttrValueDef.store();
1324         }
1325         
1326         if (provisioningAttrValueDef.isAssignToEffMembershipAssn() == false) {
1327           provisioningAttrValueDef.setAssignToMemberAssn(true);
1328           provisioningAttrValueDef.setAssignToEffMembershipAssn(true);
1329           provisioningAttrValueDef.store();
1330         }
1331 
1332         //the attributes can only be assigned to the value def
1333         // try an attribute def dependent on an attribute def name
1334         provisioningAttrValueDef.getAttributeDefScopeDelegate().assignOwnerNameEquals(attribute.getName());
1335         
1336         checkAttribute(grouperProvisioningStemName, provisioningAttrValueDef, GrouperProvisioningAttributeNames.PROVISIONING_TARGET,
1337             "pspngLdap|box1|etc", wasInCheckConfig);
1338         
1339         checkAttribute(grouperProvisioningStemName, provisioningAttrValueDef, GrouperProvisioningAttributeNames.PROVISIONING_DIRECT_ASSIGNMENT, 
1340             "If this is directly assigned or inherited from a parent folder", wasInCheckConfig);
1341         
1342         checkAttribute(grouperProvisioningStemName, provisioningAttrValueDef, GrouperProvisioningAttributeNames.PROVISIONING_STEM_SCOPE, 
1343             "If folder provisioning applies to only this folder or this folder and subfolders", wasInCheckConfig);
1344         
1345         checkAttribute(grouperProvisioningStemName, provisioningAttrValueDef, GrouperProvisioningAttributeNames.PROVISIONING_OWNER_STEM_ID, 
1346             "Stem ID of the folder where the configuration is inherited from.  This is blank if this is a direct assignment", wasInCheckConfig);
1347         
1348         checkAttribute(grouperProvisioningStemName, provisioningAttrValueDef, GrouperProvisioningAttributeNames.PROVISIONING_DO_PROVISION, 
1349             "If you should provision (default to true)", wasInCheckConfig);
1350         
1351         checkAttribute(grouperProvisioningStemName, provisioningAttrValueDef, GrouperProvisioningAttributeNames.PROVISIONING_METADATA_JSON,
1352             "generated json from the UI", wasInCheckConfig);
1353         
1354       }
1355       
1356       // https://spaces.at.internet2.edu/display/Grouper/USDU+delete+subjects+after+unresolvable+for+X+days
1357       // add usdu attributes
1358       {
1359         String usduRootStemName = UsduSettings.usduStemName();
1360         
1361         Stem usduStem = StemFinder.findByName(grouperSession, usduRootStemName, false);
1362         if (usduStem == null) {
1363           usduStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
1364             .assignDescription("folder for built in Grouper usdu objects").assignName(usduRootStemName)
1365             .save();
1366         }
1367 
1368         //see if attributeDef is there
1369         String subjectResolutionTypeDefName = usduRootStemName + ":" + UsduAttributeNames.SUBJECT_RESOLUTION_DEF;
1370         AttributeDef subjectResolutionType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
1371             subjectResolutionTypeDefName, false, new QueryOptions().secondLevelCache(false));
1372         if (subjectResolutionType == null) {
1373           subjectResolutionType = usduStem.addChildAttributeDef(UsduAttributeNames.SUBJECT_RESOLUTION_DEF, AttributeDefType.type);
1374           subjectResolutionType.setAssignToMember(true);
1375           subjectResolutionType.store();
1376         }
1377         
1378         //add a name
1379         AttributeDefName attribute = checkAttribute(usduStem, subjectResolutionType, UsduAttributeNames.SUBJECT_RESOLUTION_NAME, "has subject resolution attributes", wasInCheckConfig);
1380         
1381         //lets add some rule attributes
1382         String subjectResolutionAttrDefName = usduRootStemName + ":" + UsduAttributeNames.SUBJECT_RESOLUTION_VALUE_DEF;
1383         AttributeDef subjectResolutionAttrType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(  
1384             subjectResolutionAttrDefName, false, new QueryOptions().secondLevelCache(false));
1385         if (subjectResolutionAttrType == null) {
1386           subjectResolutionAttrType = usduStem.addChildAttributeDef(UsduAttributeNames.SUBJECT_RESOLUTION_VALUE_DEF, AttributeDefType.attr);
1387           subjectResolutionAttrType.setAssignToMemberAssn(true);
1388           subjectResolutionAttrType.setValueType(AttributeDefValueType.string);
1389           subjectResolutionAttrType.store();
1390         }
1391         
1392         //the attributes can only be assigned to the type def
1393         // try an attribute def dependent on an attribute def name
1394         subjectResolutionAttrType.getAttributeDefScopeDelegate().assignOwnerNameEquals(attribute.getName());
1395         
1396         checkAttribute(usduStem, subjectResolutionAttrType, UsduAttributeNames.SUBJECT_RESOLUTION_DATE_LAST_RESOLVED, 
1397             "yyyy/mm/dd If this subject has a date and is unresolveable, leave it. if this subject doesnt have a date, and is unresolvable, then set to currentDate.", wasInCheckConfig);
1398         
1399         checkAttribute(usduStem, subjectResolutionAttrType, UsduAttributeNames.SUBJECT_RESOLUTION_DAYS_UNRESOLVED, 
1400             "the number of days from current date minus dateLastResolved.", wasInCheckConfig);
1401         
1402         checkAttribute(usduStem, subjectResolutionAttrType, UsduAttributeNames.SUBJECT_RESOLUTION_LAST_CHECKED, 
1403             "yyyy/mm/dd the date this subject was last checked. When the USDU runs, if this subject is current unresolvable, then set to currentDate", wasInCheckConfig);
1404         
1405         checkAttribute(usduStem, subjectResolutionAttrType, UsduAttributeNames.SUBJECT_RESOLUTION_DELETE_DATE,
1406             "yyyy/mm/dd when all the memberships are removed", wasInCheckConfig);
1407       }
1408       
1409       
1410     } catch (SessionException se) {
1411       throw new RuntimeException(se);
1412     } finally {
1413       if (startedGrouperSession) {
1414         GrouperSession.stopQuietly(grouperSession);
1415       }
1416       if (!wasInCheckConfig) {
1417         inCheckConfig = false;
1418       }
1419     }
1420     
1421   }
1422 
1423   /**
1424    * @return the map of settings from grouper.properties
1425    */
1426   public static Map<String, String> typeSecuritySettings() {
1427     return GrouperConfig.retrieveConfig().propertiesMap(typeSecurityPattern);
1428   }
1429   
1430   /**
1431    * @return the map of settings from grouper.properties
1432    */
1433   public static Map<String, String> memberSortSearchSecuritySettings() {
1434     return GrouperConfig.retrieveConfig().propertiesMap(memberSortSearchSecurityPattern);
1435   }
1436   
1437   /**
1438    * make sure the grouper.hibernate.properties db settings are correct
1439    */
1440   public static void checkGrouperDb() {
1441     Properties grouperHibernateProperties = GrouperHibernateConfig.retrieveConfig().properties();
1442 
1443     //#com.p6spy.engine.spy.P6SpyDriver, oracle.jdbc.driver.OracleDriver
1444     String driverClassName = GrouperUtil.propertiesValue(
1445         grouperHibernateProperties, "hibernate.connection.driver_class");
1446     String connectionUrl = GrouperUtil.propertiesValue(
1447         grouperHibernateProperties, "hibernate.connection.url");
1448     String dbUser = GrouperUtil.propertiesValue(
1449         grouperHibernateProperties, "hibernate.connection.username");
1450     String dbPassword = GrouperUtil.propertiesValue(
1451         grouperHibernateProperties, "hibernate.connection.password");
1452     
1453     if (!checkDatabase(driverClassName, connectionUrl, dbUser, dbPassword, "grouper.hibernate.properties")) {
1454       return;
1455     }
1456     
1457     driverClassName = GrouperDdlUtils.convertUrlToDriverClassIfNeeded(connectionUrl, driverClassName);
1458     
1459     String realDriverClass = driverClassName;
1460 
1461     String spySuffix = "";
1462 
1463     //dont load class here
1464     if (driverClassName.equals("com.p6spy.engine.spy.P6SpyDriver")) {
1465       Properties spyProperties = GrouperUtil.propertiesFromResourceName("spy.properties");
1466       realDriverClass = StringUtils.defaultString(GrouperUtil.propertiesValue(spyProperties, "realdriver"));
1467       spySuffix = ", and spy.properties";
1468     }
1469     
1470     //try to check the hibernate dialect
1471     boolean isDriverOracle = realDriverClass.toLowerCase().contains("oracle");
1472     boolean isDriverPostgres = realDriverClass.toLowerCase().contains("postgres");
1473     boolean isDriverMysql = realDriverClass.toLowerCase().contains("mysql");
1474     boolean isDriverHsql = realDriverClass.toLowerCase().contains("hsql");
1475     boolean isDriverSqlServer = realDriverClass.toLowerCase().contains("sqlserver") 
1476       || realDriverClass.toLowerCase().contains("jtds");
1477     
1478     String dialect = StringUtils.defaultString(GrouperUtil.propertiesValue(grouperHibernateProperties,"hibernate.dialect"));
1479     
1480     dialect = GrouperDdlUtils.convertUrlToHibernateDialectIfNeeded(connectionUrl, dialect);
1481     
1482     boolean isDialectOracle = dialect.toLowerCase().contains("oracle");
1483     boolean isDialectPostgres = dialect.toLowerCase().contains("postgres");
1484     boolean isDialectMysql = dialect.toLowerCase().contains("mysql");
1485     boolean isDialectHsql = dialect.toLowerCase().contains("hsql");
1486     boolean isDialectSqlServer = dialect.toLowerCase().contains("sqlserver");
1487     
1488     if (GrouperConfig.retrieveConfig().propertyValueBoolean("db.log.driver.mismatch", true)) {
1489       if ((isDriverOracle && !isDialectOracle) || (isDriverPostgres && !isDialectPostgres) 
1490           || (isDriverMysql && !isDialectMysql) || (isDriverHsql && !isDialectHsql)
1491           || (!isDriverOracle && isDialectOracle) || (!isDriverPostgres && isDialectPostgres) 
1492           || (!isDriverMysql && isDialectMysql) || (!isDriverHsql && isDialectHsql)
1493           || (!isDriverSqlServer && isDialectSqlServer) || (isDriverSqlServer && !isDialectSqlServer)) {
1494         String error = "Grouper error: detected mismatch in hibernate.connection.driver_class ("
1495                 + realDriverClass + ") and hibernate.dialect (" + dialect 
1496                 + ") in grouper.hibernate.properties" + spySuffix;
1497         System.err.println(error);
1498         LOG.error(error);
1499       }
1500     }    
1501   }
1502 
1503   /**
1504    * test a database connection
1505    * @param driverClassName
1506    * @param connectionUrl
1507    * @param dbUser
1508    * @param dbPassword
1509    * @param databaseDescription friendly error description when there is a problem
1510    * @return true if it is ok, false if there is a problem
1511    */
1512   public static boolean checkDatabase(String driverClassName, String connectionUrl, String dbUser, String dbPassword,
1513       String databaseDescription) {
1514     try {
1515       
1516       if (StringUtils.isBlank(connectionUrl)) {
1517         String error = "Error finding connection url from " + databaseDescription;
1518         System.err.println("Grouper error: " + error);
1519         LOG.error(error);
1520         return false;
1521         
1522       }
1523       
1524       dbPassword = Morph.decryptIfFile(dbPassword);
1525       
1526       driverClassName = GrouperDdlUtils.convertUrlToDriverClassIfNeeded(connectionUrl, driverClassName);
1527       
1528       Class driverClass = null;
1529       try {
1530         driverClass = GrouperUtil.forName(driverClassName);
1531       } catch (Exception e) {
1532         String error = "Error finding database driver class from " + databaseDescription + ": " 
1533           + driverClassName
1534           + ", perhaps you did not put the database driver jar in the /opt/grouper/grouperWebapp/WEB-INF/lib dir or lib dir, " +
1535               "or you have the wrong driver listed";
1536         System.err.println("Grouper error: " + error + ": " + ExceptionUtils.getFullStackTrace(e));
1537         LOG.error(error, e);
1538         return false;
1539       }
1540       
1541       //check out P6Spy
1542       String spyInsert = "";
1543       //dont load class here
1544       if (driverClass.getName().equals("com.p6spy.engine.spy.P6SpyDriver")) {
1545         spyInsert = " and spy.properties, ";
1546         checkResource("spy.properties");
1547         Properties spyProperties = GrouperUtil.propertiesFromResourceName("spy.properties");
1548         driverClassName = StringUtils.defaultString(GrouperUtil.propertiesValue(spyProperties,"realdriver"));
1549         try {
1550           driverClass = GrouperUtil.forName(driverClassName);
1551         } catch (Exception e) {
1552           String error = "Error finding database driver class from spy.properties: '" 
1553             + driverClassName
1554             + "', perhaps you did not put the database driver jar in the /opt/grouper/grouperWebapp/WEB-INF/lib dir or lib dir, " +
1555                 "or you have the wrong driver listed";
1556           System.err.println("Grouper error: " + error + ": " + ExceptionUtils.getFullStackTrace(e));
1557           LOG.error(error, e);
1558           return false;
1559         }
1560       }
1561       
1562       //lets make a db connection
1563       Connection dbConnection = null;
1564       try {
1565         dbConnection = DriverManager.getConnection(connectionUrl, dbUser, dbPassword);
1566         @SuppressWarnings("unused")
1567         String version = dbConnection.getMetaData().getDatabaseProductVersion();
1568         return true;
1569       } catch( SQLException sqlException) {
1570         String error = "Error connecting to the database with credentials from " + databaseDescription + ", "
1571           + spyInsert + "url: " + connectionUrl + ", driver: " + driverClassName + ", user: " + dbUser;
1572         System.out.println("Grouper error: " + error + ", " + ExceptionUtils.getFullStackTrace(sqlException));
1573         LOG.error(error, sqlException);
1574       } finally {
1575         GrouperUtil.closeQuietly(dbConnection);
1576       }
1577       
1578     } catch (Exception e) {
1579       String error = "Error verifying " + databaseDescription + " database configuration: ";
1580       System.err.println("Grouper error: " + error + ExceptionUtils.getFullStackTrace(e));
1581       LOG.error(error, e);
1582     }
1583     return false;
1584   }
1585   
1586     
1587   /**
1588    * make sure properties file properties match up
1589    */
1590   private static void checkConfigProperties() {
1591 
1592     //checkConfigProperties(GROUPER_PROPERTIES_NAME, "grouper.example.properties");
1593     //checkConfigProperties("grouper.hibernate.properties", "grouper.hibernate.example.properties");
1594     //checkConfigProperties("morphString.properties", "morphString.example.properties");
1595     if (GrouperUtil.isBlank(MorphStringConfig.retrieveConfig().propertyValueString("encrypt.key"))) {
1596       String error = "Error: Grouper expects an encrpyt key (generally a long random alphanumeric string) \"encrypt.key\" in properties file morphString.properties";
1597       System.err.println(error);
1598       LOG.error(error);
1599     }
1600     checkGrouperConfigDbChange();
1601     checkGrouperConfigGroupNameValidators();
1602     checkGrouperConfigIncludeExcludeAndGroups();
1603     checkGrouperConfigAutocreateGroups();
1604     checkGrouperConfigCustomComposites();
1605   }
1606 
1607   /**
1608    * check the grouper loader db configs
1609    */
1610   public static void checkGrouperLoaderConfigDbs() {
1611 
1612     //db.warehouse.user = mylogin
1613     //db.warehouse.pass = secret
1614     //db.warehouse.url = jdbc:mysql://localhost:3306/grouper
1615     //db.warehouse.driver = com.mysql.jdbc.Driver
1616     //make sure sequences are ok
1617     Map<String, String> dbMap = GrouperLoaderConfig.retrieveConfig().propertiesMap( 
1618         grouperLoaderDbPattern);
1619     while (dbMap.size() > 0) {
1620       //get one
1621       String dbKey = dbMap.keySet().iterator().next();
1622       //get the database name
1623       Matcher matcher = grouperLoaderDbPattern.matcher(dbKey);
1624       matcher.matches();
1625       String dbName = matcher.group(1);
1626       boolean missingOne = false;
1627       //now find all 4 required keys
1628       String userKey = "db." + dbName + ".user";
1629       if (!dbMap.containsKey(userKey)) {
1630         String error = "cannot find grouper-loader.properties key: " + userKey; 
1631         System.out.println("Grouper error: " + error);
1632         LOG.error(error);
1633         missingOne = true;
1634       }
1635       String passKey = "db." + dbName + ".pass";
1636       if (!dbMap.containsKey(passKey)) {
1637         String error = "cannot find grouper-loader.properties key: " + passKey; 
1638         System.out.println("Grouper error: " + error);
1639         LOG.error(error);
1640         missingOne = true;
1641       }
1642       String urlKey = "db." + dbName + ".url";
1643       if (!dbMap.containsKey(urlKey)) {
1644         String error = "cannot find grouper-loader.properties key: " + urlKey; 
1645         System.out.println("Grouper error: " + error);
1646         LOG.error(error);
1647         missingOne = true;
1648       }
1649       String driverKey = "db." + dbName + ".driver";
1650       if (!dbMap.containsKey(driverKey)) {
1651         
1652         //its ok unless we cant convert from url...
1653         if (!StringUtils.isBlank(urlKey) && StringUtils.isBlank(GrouperDdlUtils.convertUrlToDriverClassIfNeeded(dbMap.get(urlKey), null))) {
1654         
1655         String error = "cannot find grouper-loader.properties key: " + driverKey; 
1656         System.out.println("Grouper error: " + error);
1657         LOG.error(error);
1658         missingOne = true;
1659       }
1660       }
1661       if (missingOne) {
1662         return;
1663       }
1664       String user = dbMap.get(userKey);
1665       String password = dbMap.get(passKey);
1666       String url = dbMap.get(urlKey);
1667       String driver = dbMap.get(driverKey);
1668 
1669       //try to connect to database
1670       checkDatabase(driver, url, user, password, "grouper-loader.properties database name '" + dbName + "'");
1671       
1672       dbMap.remove(userKey);
1673       dbMap.remove(passKey);
1674       dbMap.remove(urlKey);
1675       dbMap.remove(driverKey);
1676 
1677     }
1678     
1679   }
1680   
1681   /**
1682    * check the grouper loader other jobs configs
1683    */
1684   public static void checkGrouperLoaderOtherJobs() {
1685 
1686     //otherJob.duo.class = 
1687     //otherJob.duo.quartzCron = 
1688     //otherJob.duo.priority = 
1689     
1690     //make sure sequences are ok
1691     Map<String, String> otherJobMap = GrouperLoaderConfig.retrieveConfig().propertiesMap(
1692         grouperLoaderOtherJobPattern);
1693     while (otherJobMap.size() > 0) {
1694       //get one
1695       String otherJobKey = otherJobMap.keySet().iterator().next();
1696       //get the database name
1697       Matcher matcher = grouperLoaderOtherJobPattern.matcher(otherJobKey);
1698       matcher.matches();
1699       String otherJobName = matcher.group(1);
1700       boolean missingOne = false;
1701       //now find all required keys
1702       String classKey = "otherJob." + otherJobName + ".class";
1703       if (!otherJobMap.containsKey(classKey)) {
1704         String error = "cannot find grouper-loader.properties key: " + classKey; 
1705         System.out.println("Grouper error: " + error);
1706         LOG.error(error);
1707         missingOne = true;
1708       }
1709       String cronKey = "otherJob." + otherJobName + ".quartzCron";
1710       if (!otherJobMap.containsKey(cronKey)) {
1711         String error = "cannot find grouper-loader.properties key: " + cronKey; 
1712         System.out.println("Grouper error: " + error);
1713         LOG.error(error);
1714         missingOne = true;
1715       }
1716       
1717       String priorityKey = "otherJob." + otherJobName + ".priority";
1718 
1719       if (missingOne) {
1720         return;
1721       }
1722       String className = otherJobMap.get(classKey);
1723       @SuppressWarnings("unused")
1724       String cronName = otherJobMap.get(cronKey);
1725       
1726       //check the classname
1727       try {
1728         
1729         @SuppressWarnings("unused")
1730         Class<? extends Job> theClass = GrouperUtil.forName(className);
1731         
1732       } catch (Exception e) {
1733         String error = "problem finding class: " + classKey + " from grouper-loader.properties: " + className 
1734           + ", " + ExceptionUtils.getFullStackTrace(e);
1735         System.out.println("Grouper error: " + error);
1736         LOG.error(error);
1737         
1738       }
1739       
1740       otherJobMap.remove(classKey);
1741       otherJobMap.remove(cronKey);
1742       otherJobMap.remove(priorityKey);
1743 
1744     }
1745     
1746   }
1747   
1748   /**
1749    * check the grouper loader consumer configs
1750    */
1751   public static void checkGrouperLoaderConsumers() {
1752 
1753     //changeLog.consumer.ldappc.class = 
1754     //changeLog.consumer.ldappc.quartz.cron
1755     
1756     //make sure sequences are ok
1757     Map<String, String> consumerMap = GrouperLoaderConfig.retrieveConfig().propertiesMap(
1758         grouperLoaderConsumerPattern);
1759     while (consumerMap.size() > 0) {
1760       //get one
1761       String consumerKey = consumerMap.keySet().iterator().next();
1762       //get the database name
1763       Matcher matcher = grouperLoaderConsumerPattern.matcher(consumerKey);
1764       matcher.matches();
1765       String consumerName = matcher.group(1);
1766       boolean missingOne = false;
1767       //now find all 4 required keys
1768       String classKey = "changeLog.consumer." + consumerName + ".class";
1769       if (!consumerMap.containsKey(classKey)) {
1770         String error = "cannot find grouper-loader.properties key: " + classKey; 
1771         System.out.println("Grouper error: " + error);
1772         LOG.error(error);
1773         missingOne = true;
1774       }
1775       String cronKey = "changeLog.consumer." + consumerName + ".quartzCron";
1776       if (!consumerMap.containsKey(cronKey)) {
1777         String error = "cannot find grouper-loader.properties key: " + cronKey; 
1778         System.out.println("Grouper error: " + error);
1779         LOG.error(error);
1780         missingOne = true;
1781       }
1782       if (missingOne) {
1783         return;
1784       }
1785       String className = consumerMap.get(classKey);
1786       @SuppressWarnings("unused")
1787       String cronName = consumerMap.get(cronKey);
1788       
1789       //check the classname
1790       try {
1791         
1792         Class<?> theClass = GrouperUtil.forName(className);
1793         if (!ChangeLogConsumerBase.class.isAssignableFrom(theClass)) {
1794           String error = "class in grouper-loader.properties: " + classKey + " must extend : " 
1795             + ChangeLogConsumerBase.class.getName() + " : offendingClass: " + className; 
1796           System.out.println("Grouper error: " + error);
1797           LOG.error(error);
1798         }
1799         
1800       } catch (Exception e) {
1801         String error = "problem finding class: " + classKey + " from grouper-loader.properties: " + className 
1802           + ", " + ExceptionUtils.getFullStackTrace(e);
1803         System.out.println("Grouper error: " + error);
1804         LOG.error(error);
1805         
1806       }
1807       
1808       consumerMap.remove(classKey);
1809       consumerMap.remove(cronKey);
1810 
1811     }
1812     
1813   }
1814 
1815   /**
1816    * check custom composites
1817    */
1818   private static void checkGrouperConfigCustomComposites() {
1819     //#grouper.membership.customComposite.uiKey.0 = customCompositeMinusEmployees
1820     //#grouper.membership.customComposite.compositeType.0 = complement
1821     //#grouper.membership.customComposite.groupName.0 = ref:activeEmployees
1822 
1823     //make sure sequences are ok
1824     Map<String, String> keys = GrouperConfig.retrieveConfig().propertiesMap(customCompositePattern);
1825     int i=0;
1826     while (true) {
1827       boolean foundOne = false;
1828       String uiKeyKey = "grouper.membership.customComposite.uiKey." + i;
1829       String compositeTypeKey = "grouper.membership.customComposite.compositeType." + i;
1830       String groupNameKey = "grouper.membership.customComposite.groupName." + i;
1831 
1832       foundOne = assertAndRemove(GROUPER_PROPERTIES_NAME, keys,
1833           new String[]{uiKeyKey, compositeTypeKey, groupNameKey});
1834       if (!foundOne) {
1835         break;
1836       }
1837       i++;
1838     }
1839     if (keys.size() > 0) {
1840       String error = "in property file: grouper.properties, these properties " +
1841           "are misspelled or non-sequential: " + GrouperUtil.setToString(keys.keySet());
1842       System.err.println("Grouper error: " + error);
1843       LOG.error(error);
1844     }
1845 
1846   }
1847   
1848   /**
1849    * check the grouper config group name validators
1850    */
1851   private static void checkGrouperConfigGroupNameValidators() {
1852     //#group.attribute.validator.attributeName.0=extension
1853     //#group.attribute.validator.regex.0=^[a-zA-Z0-9]+$
1854     //#group.attribute.validator.vetoMessage.0=Group ID '$attributeValue$' is invalid since it must contain only alpha-numerics
1855     
1856     //make sure sequences are ok
1857     Map<String, String> validatorKeys = GrouperConfig.retrieveConfig().propertiesMap(groupValidatorPattern);
1858     int i=0;
1859     while (true) {
1860       boolean foundOne = false;
1861       String attributeNameKey = "group.attribute.validator.attributeName." + i;
1862       String regexKey = "group.attribute.validator.regex." + i;
1863       String vetoMessageKey = "group.attribute.validator.vetoMessage." + i;
1864 
1865       foundOne = assertAndRemove(GROUPER_PROPERTIES_NAME, validatorKeys, 
1866           new String[]{attributeNameKey, regexKey, vetoMessageKey});
1867       if (!foundOne) {
1868         break;
1869       }
1870       i++;
1871     }
1872     if (validatorKeys.size() > 0) {
1873       String error = "in property file: grouper.properties, these properties " +
1874           "are misspelled or non-sequential: " + GrouperUtil.setToString(validatorKeys.keySet());
1875       System.err.println("Grouper error: " + error);
1876       LOG.error(error);
1877     }
1878 
1879   }
1880 
1881   /**
1882    * check the grouper config group name validators
1883    */
1884   private static void checkGrouperConfigAutocreateGroups() {
1885     //#configuration.autocreate.group.name.0 = etc:uiUsers
1886     //#configuration.autocreate.group.description.0 = users allowed to log in to the UI
1887     //#configuration.autocreate.group.subjects.0 = johnsmith
1888     
1889     //make sure sequences are ok
1890     Map<String, String> validatorKeys = GrouperConfig.retrieveConfig().propertiesMap(autocreateGroupsPattern);
1891     int i=0;
1892     while (true) {
1893       boolean foundOne = false;
1894       String nameKey = "configuration.autocreate.group.name." + i;
1895       String descriptionKey = "configuration.autocreate.group.description." + i;
1896       String subjectsKey = "configuration.autocreate.group.subjects." + i;
1897 
1898       foundOne = assertAndRemove(GROUPER_PROPERTIES_NAME, validatorKeys, 
1899           new String[]{nameKey, descriptionKey, subjectsKey});
1900 
1901       if (!foundOne) {
1902         break;
1903       }
1904       i++;
1905     }
1906     if (validatorKeys.size() > 0) {
1907       String error = "in property file: grouper.properties, these properties " +
1908           "are misspelled or non-sequential: " + GrouperUtil.setToString(validatorKeys.keySet());
1909       System.err.println("Grouper error: " + error);
1910       LOG.error(error);
1911     }
1912 
1913   }
1914 
1915   /**
1916    * check the grouper config group name validators
1917    */
1918   private static void checkGrouperConfigIncludeExcludeAndGroups() {
1919     //#grouperIncludeExclude.requireGroup.name.0 = activeEmployee
1920     //#grouperIncludeExclude.requireGroup.group.0 = school:community:activeEmployee
1921     //#grouperIncludeExclude.requireGroup.description.0 = If value is true, members of the overall group must be an active employee.  Otherwise, leave this value not filled in.
1922     
1923     //make sure sequences are ok
1924     Map<String, String> validatorKeys = GrouperConfig.retrieveConfig().propertiesMap(includeExcludeAndGroupPattern);
1925     int i=0;
1926     while (true) {
1927       boolean foundOne = false;
1928       String nameKey = "grouperIncludeExclude.requireGroup.name." + i;
1929       String attributeOrTypeKey = "grouperIncludeExclude.requireGroup.attributeOrType." + i;
1930       String regexKey = "grouperIncludeExclude.requireGroup.group." + i;
1931       String vetoMessageKey = "grouperIncludeExclude.requireGroup.description." + i;
1932 
1933       foundOne = assertAndRemove(GROUPER_PROPERTIES_NAME, validatorKeys, 
1934           new String[]{nameKey, attributeOrTypeKey, regexKey, vetoMessageKey});
1935       if (!foundOne) {
1936         break;
1937       }
1938       i++;
1939     }
1940     if (validatorKeys.size() > 0) {
1941       String error = "in property file: grouper.properties, these properties " +
1942           "are misspelled or non-sequential: " + GrouperUtil.setToString(validatorKeys.keySet());
1943       System.err.println("Grouper error: " + error);
1944       LOG.error(error);
1945     }
1946 
1947   }
1948 
1949   /**
1950    * check db change properties in the grouper config
1951    */
1952   private static void checkGrouperConfigDbChange() {
1953     //make sure sequences are ok
1954     Map<String, String> dbChangeKeys = GrouperConfig.retrieveConfig().propertiesMap(dbChangePattern);
1955     int i=0;
1956     //db.change.allow.user.0=grouper3
1957     //db.change.allow.url.0=jdbc:mysql://localhost:3306/grouper3
1958     while (true) {
1959       boolean foundOne = false;
1960       String allowUserKey = "db.change.allow.user." + i;
1961       String allowUrlKey = "db.change.allow.url." + i;
1962       String denyUserKey = "db.change.deny.user." + i;
1963       String denyUrlKey = "db.change.deny.url." + i;
1964       //note, not short circuit OR since needs to evaluate both
1965       foundOne = assertAndRemove(GROUPER_PROPERTIES_NAME, dbChangeKeys, new String[]{allowUserKey, allowUrlKey})
1966         | assertAndRemove(GROUPER_PROPERTIES_NAME, dbChangeKeys, new String[]{denyUserKey, denyUrlKey});
1967       if (!foundOne) {
1968         break;
1969       }
1970       i++;
1971     }
1972     if (dbChangeKeys.size() > 0) {
1973       String error = "in property file: grouper.properties, these properties " +
1974           "are misspelled or non-sequential: " + GrouperUtil.setToString(dbChangeKeys.keySet());
1975       System.err.println("Grouper error: " + error);
1976       LOG.error(error);
1977     }
1978   }
1979 
1980   /**
1981    * if one there, then they all must be there, and remove, return true if found one
1982    * @param resourceName
1983    * @param set of properties that match this pattern
1984    * @param propertiesNames
1985    * @return true if found one
1986    */
1987   public static boolean assertAndRemove(String resourceName, 
1988       Map<String, String> set, String[] propertiesNames) {
1989     boolean foundOne = false;
1990     for (String propertyName : propertiesNames) {
1991       if (set.containsKey(propertyName)) {
1992         foundOne = true;
1993         break;
1994       }
1995     }
1996     if (foundOne) {
1997       for (String propertyName : propertiesNames) {
1998         if (set.containsKey(propertyName)) {
1999           set.remove(propertyName);
2000         } else {
2001           String error = "expecting property " + propertyName 
2002             + " in config file: " + resourceName + " since related properties exist";
2003           System.err.println("Grouper error: " + error);
2004           LOG.error(error);
2005         }
2006       }
2007     }
2008     return foundOne;
2009   }
2010   
2011   /** properties in manifest for version */
2012   private static final String[] versionProperties = new String[]{
2013     "Implementation-Version","Version"};
2014   
2015   /**
2016    * get the version from the manifest of a jar
2017    * @param sampleClass
2018    * @return the version
2019    * @throws Exception
2020    */
2021   public static String jarVersion(Class sampleClass) throws Exception {
2022     return manifestProperty(sampleClass, versionProperties);
2023   }
2024 
2025   /**
2026    * get the version from the manifest of a jar
2027    * @param sampleClass
2028    * @param propertyNames that we are looking for (usually just one)
2029    * @return the version
2030    * @throws Exception
2031    */
2032   public static String manifestProperty(Class sampleClass, String[] propertyNames) throws Exception {
2033     File jarFile = GrouperUtil.jarFile(sampleClass, true);
2034     URL manifestUrl = new URL("jar:file:" + jarFile.getCanonicalPath() + "!/META-INF/MANIFEST.MF");
2035     Manifest manifest = new Manifest(manifestUrl.openStream());
2036     Map<String, Attributes> attributeMap = manifest.getEntries();
2037     String value = null;
2038     for (String propertyName : propertyNames) {
2039       value = manifest.getMainAttributes().getValue(propertyName);
2040       if (!StringUtils.isBlank(value)) {
2041         break;
2042       }
2043     }
2044     if (value == null) {
2045       OUTER:
2046       for (Attributes attributes: attributeMap.values()) {
2047         for (String propertyName : propertyNames) {
2048           value = attributes.getValue(propertyName);
2049           if (!StringUtils.isBlank(value)) {
2050             break OUTER;
2051           }
2052         }
2053       }
2054     }
2055     if (value == null) {
2056       
2057       for (Attributes attributes: attributeMap.values()) {
2058         for (Object key : attributes.keySet()) {
2059           LOG.info(jarFile.getName() + ", " + key + ": " + attributes.getValue((Name)key));
2060         }
2061       }
2062       Attributes attributes = manifest.getMainAttributes();
2063       for (Object key : attributes.keySet()) {
2064         LOG.info(jarFile.getName() + ", " + key + ": " + attributes.getValue((Name)key));
2065       }
2066     }
2067     return value;
2068   }
2069 
2070   /** match something like this: db.change.allow.url.1 */
2071   private static Pattern dbChangePattern = Pattern.compile(
2072       "^db\\.change\\.(deny|allow)\\.(user|url).\\d+$");
2073   
2074   /** match something like this: group.attribute.validator.attributeName.0 */
2075   private static Pattern groupValidatorPattern = Pattern.compile(
2076       "^group\\.attribute\\.validator\\.(attributeName|regex|vetoMessage)\\.\\d+$");
2077 
2078   /** match something like this: grouper.membership.customComposite.uiKey.0 */
2079   private static Pattern customCompositePattern = Pattern.compile(
2080       "^grouper\\.membership\\.customComposite\\.(uiKey|compositeType|groupName)\\.\\d+$");
2081   
2082   /** match something like this: grouperIncludeExclude.requireGroup.name.0 */
2083   private static Pattern includeExcludeAndGroupPattern = Pattern.compile(
2084       "^grouperIncludeExclude\\.requireGroup\\.(name|attributeOrType|group|description)\\.\\d+$");
2085   
2086   /** match something like this: configuration.autocreate.group.name.0 */
2087   private static Pattern autocreateGroupsPattern = Pattern.compile(
2088       "^configuration\\.autoCreate\\.(name|description|subjects)\\.\\d+$");
2089   
2090   /**
2091    * match something like this: db.warehouse.pass
2092    */
2093   private static Pattern grouperLoaderDbPattern = Pattern.compile(
2094       "^db\\.(\\w+)\\.(pass|url|driver|user)$");
2095   
2096   /**
2097    * match something like this: changeLog.consumer.ldappc.class, changeLog.consumer.ldappc.quartzCron
2098    */
2099   public static Pattern grouperLoaderConsumerPattern = Pattern.compile(
2100       "^changeLog\\.consumer\\.(\\w+)\\.(class|quartzCron)$");
2101   
2102   /**
2103    * match something like this: changeLog.consumer.ldappc.class, changeLog.consumer.ldappc.quartzCron
2104    */
2105   public static Pattern messagingListenerConsumerPattern = Pattern.compile(
2106       "^messaging\\.listener\\.(\\w+)\\.(.*)$");
2107   
2108   /**
2109    * match something like this: otherJob.duo.class, otherJob.duo.quartzCron, otherJob.duo.priority
2110    */
2111   public static Pattern grouperLoaderOtherJobPattern = Pattern.compile(
2112       "^otherJob\\.(\\w+)\\.(class|quartzCron|priority)$");
2113   
2114   /**
2115    * <pre>
2116    * match type security
2117    * match: security.typeName.wheelOnly
2118    * match: security.typeName.allowOnlyGroup
2119    * </pre>
2120    */
2121   public static final Pattern typeSecurityPattern = Pattern.compile(
2122       "^security\\.types\\.(.*)\\.(wheelOnly|allowOnlyGroup)$");
2123   
2124   /**
2125    * <pre>
2126    * match security for search and sort strings
2127    * match: security.member.sort.string[0-4].allowOnlyGroup
2128    * match: security.member.sort.string[0-4].wheelOnly
2129    * match: security.member.search.string[0-4].allowOnlyGroup
2130    * match: security.member.search.string[0-4].wheelOnly
2131    * </pre>
2132    */
2133   public static final Pattern memberSortSearchSecurityPattern = Pattern.compile(
2134       "^security\\.member\\.(sort|search)\\.(string[0-4])\\.(wheelOnly|allowOnlyGroup)$");
2135   
2136   /**
2137    * return true if this is an exception case, dont worry about it
2138    * @param resourceName
2139    * @param propertyName
2140    * @param missingPropertyInFile true if missing property in file, false if
2141    * extra property in file
2142    * @return true if exception case
2143    */
2144   public static boolean nonStandardProperty(String resourceName, String propertyName,
2145       boolean missingPropertyInFile) {
2146     if (StringUtils.equals(resourceName, GROUPER_PROPERTIES_NAME)) {
2147       if (dbChangePattern.matcher(propertyName).matches()) {
2148         return true;
2149       }
2150       if (groupValidatorPattern.matcher(propertyName).matches()) {
2151         return true;
2152       }
2153       if (includeExcludeAndGroupPattern.matcher(propertyName).matches()) {
2154         return true;
2155       }
2156       if (autocreateGroupsPattern.matcher(propertyName).matches()) {
2157         return true;
2158       }
2159       if (typeSecurityPattern.matcher(propertyName).matches()) {
2160         return true;
2161       }
2162       if (memberSortSearchSecurityPattern.matcher(propertyName).matches()) {
2163         return true;
2164       }
2165       if (customCompositePattern.matcher(propertyName).matches()) {
2166         return true;
2167       }
2168     }
2169     if (StringUtils.equals(resourceName, "grouper.hibernate.properties")
2170       || !missingPropertyInFile) {
2171       return true;
2172     }
2173     if (StringUtils.equals(resourceName, "grouper-loader.properties")) {
2174       if (grouperLoaderDbPattern.matcher(propertyName).matches()) {
2175         return true;
2176       }
2177     }
2178     
2179     return false;
2180   }
2181   
2182   /**
2183    * return if in check config
2184    * @return if in check config
2185    */
2186   public static boolean isInCheckConfig() {
2187     return inCheckConfig;
2188   }
2189   
2190   /**
2191    * compare a properties file with an example file, compare all the properties
2192    * @param resourceName
2193    * @param resourceExampleName
2194    */
2195   public static void checkConfigProperties(String resourceName, 
2196       String resourceExampleName) {
2197     
2198     Properties propertiesFromFile = GrouperUtil.propertiesFromResourceName(resourceName);
2199     Properties propertiesFromExample = GrouperUtil.propertiesFromResourceName(resourceExampleName);
2200     String exampleFileContents = GrouperUtil.readResourceIntoString(resourceExampleName, false);
2201     
2202     //find properties missing from file:
2203     Set<String> missingProps = new HashSet<String>();
2204     for (String key: (Set<String>)(Object)propertiesFromExample.keySet()) {
2205       if (!propertiesFromFile.containsKey(key)) {
2206         if (!nonStandardProperty(resourceName, key, true)) {
2207           missingProps.add(key);
2208         }
2209       }
2210     }
2211     if (missingProps.size() > 0) {
2212       String error = "missing from file: " + resourceName + ", the following " +
2213           "properties (which are in the example file: " + resourceExampleName
2214           + "): " + GrouperUtil.setToString(missingProps);
2215       System.err.println("Grouper warning: " + error);
2216       LOG.warn(error);
2217     }
2218     
2219     //find extra properties in file:
2220     missingProps.clear();
2221     for (String key: (Set<String>)(Object)propertiesFromFile.keySet()) {
2222       //dont look in properties, look in file, since could be commented out
2223       if (!exampleFileContents.contains(key)) {
2224         if (!nonStandardProperty(resourceName, key, false)) {
2225           missingProps.add(key);
2226         }
2227       }
2228     }
2229     if (missingProps.size() > 0) {
2230       String error = "properties are in file: " + resourceName + " (but not in " +
2231           "the example file: " + resourceExampleName
2232           + "): " + GrouperUtil.setToString(missingProps);
2233       System.err.println("Grouper warning: " + error);
2234       LOG.warn(error);
2235     }
2236   }
2237 
2238   /**
2239    * make sure an attribute is there or add it if not
2240    * @param stem
2241    * @param attributeDef 
2242    * @param extension
2243    * @param description
2244    * @param logAutocreate 
2245    * @return the attribute def name
2246    */
2247   private static AttributeDefName checkAttribute(Stem stem, AttributeDef attributeDef, String extension, String description, boolean logAutocreate) {
2248     return checkAttribute(stem, attributeDef, extension, extension, description, logAutocreate);
2249   }
2250   
2251   /**
2252    * make sure an attribute is there or add it if not
2253    * @param stem
2254    * @param attributeDef 
2255    * @param extension
2256    * @param displayExtension
2257    * @param description
2258    * @param logAutocreate 
2259    * @return the attribute def name
2260    */
2261   public static AttributeDefName checkAttribute(Stem stem, AttributeDef attributeDef, String extension, String displayExtension, String description, boolean logAutocreate) {
2262     String attributeDefNameName = stem.getName() + ":" + extension;
2263     
2264     //dont cache since if not there, that not there will be cached
2265     AttributeDefName attributeDefName = GrouperDAOFactory.getFactory().getAttributeDefName().findByNameSecure(attributeDefNameName, false, new QueryOptions().secondLevelCache(false));
2266 
2267     if (attributeDefName == null) {
2268       try {
2269         attributeDefName = stem.addChildAttributeDefName(attributeDef, extension, displayExtension);
2270       } catch (RuntimeException theException) {
2271         GrouperUtil.sleep(3000);
2272         attributeDefName = GrouperDAOFactory.getFactory().getAttributeDefName().findByNameSecure(attributeDefNameName, false, new QueryOptions().secondLevelCache(false));
2273         if (attributeDefName == null) {
2274           throw theException;
2275         }
2276         return attributeDefName;
2277       }
2278       attributeDefName.setDescription(description);
2279       attributeDefName.store();
2280       
2281       if (logAutocreate) {
2282         String error = "auto-created attributeDefName: " + attributeDefNameName;
2283         System.err.println("Grouper note: " + error);
2284         LOG.warn(error);
2285       }
2286     }
2287     return attributeDefName;
2288   }
2289 
2290   /**
2291    * return the stem name where the attribute loader attributes go, without colon on end
2292    * @return stem name
2293    */
2294   public static String attributeLoaderStemName() {
2295     String rootStemName = attributeRootStemName();
2296     
2297     //namespace this separate from other builtins
2298     rootStemName += ":attrLoader";
2299     return rootStemName;
2300   }
2301 
2302   /**
2303    * root stem where attributes live
2304    * @return attribute built in stem name
2305    */
2306   public static String attributeRootStemName() {
2307     String rootStemName = GrouperConfig.retrieveConfig().propertyValueString("grouper.attribute.rootStem");
2308     if (StringUtils.isBlank(rootStemName)) {
2309       throw new RuntimeException("If autoconfiguring attributes, you need to configure a root stem");
2310     }
2311     return rootStemName;
2312   }
2313   
2314   /**
2315    * 
2316    * @return the stem name
2317    */
2318   public static String loaderMetadataStemName() {
2319     return GrouperConfig.retrieveConfig().propertyValueString("grouper.rootStemForBuiltinObjects", "etc") + ":attribute:loaderMetadata";
2320   }
2321 
2322   /**
2323    * call this to init data in grouper
2324    */
2325   public static void checkObjects() {
2326     checkGroups();
2327     checkAttributes();
2328     GrouperStartup.initLoaderType();
2329     checkConfig2();
2330   }
2331   
2332   /**
2333    * make sure configured attributes are there 
2334    */
2335   private static void checkAttributes() {
2336     
2337     boolean autoconfigure = GrouperConfig.retrieveConfig().propertyValueBoolean("grouper.attribute.loader.autoconfigure", true);
2338     if (!autoconfigure) {
2339       return;
2340     }
2341 
2342     boolean wasInCheckConfig = inCheckConfig;
2343     if (!wasInCheckConfig) {
2344       inCheckConfig = true;
2345     }
2346 
2347     GrouperSession grouperSession = null;
2348     boolean startedGrouperSession = false;
2349     try {
2350       grouperSession = GrouperSession.staticGrouperSession(false);
2351 
2352       if (grouperSession == null) {
2353         grouperSession = GrouperSession.startRootSession();
2354         startedGrouperSession = true;
2355       }
2356       
2357       //clear this for tests
2358       ExpirableCache.clearAll();
2359         
2360       legacyAttributeBaseStem(grouperSession);
2361       
2362       {
2363         StemUniqueNameCaseInsensitiveHook.registerHookIfNecessary();
2364         GroupUniqueNameCaseInsensitiveHook.registerHookIfNecessary();
2365         AttributeDefUniqueNameCaseInsensitiveHook.registerHookIfNecessary();
2366         AttributeDefNameUniqueNameCaseInsensitiveHook.registerHookIfNecessary();
2367       }
2368       
2369       boolean autoAssignTheAutoAssignAttributes = false;
2370       AttributeDefName attributeAutoCreateMarker = null;
2371       AttributeDef attributeAutoCreateDef = null;
2372       AttributeDefName autoAssignIfName = null;
2373       AttributeDefName autoAssignThenNames = null;
2374       {
2375         
2376         String attributeAutoCreateStemName = AttributeAutoCreateHook.attributeAutoCreateStemName();
2377         
2378         Stem attributeAutoCreateStem = StemFinder.findByName(grouperSession, attributeAutoCreateStemName, false);
2379         if (attributeAutoCreateStem == null) {
2380           attributeAutoCreateStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
2381             .assignDescription("folder for attribute autocreate objects").assignName(attributeAutoCreateStemName)
2382             .save();
2383         }
2384 
2385         //see if attributeDef is there
2386         String attributeAutoCreateDefName = attributeAutoCreateStemName + ":" + AttributeAutoCreateHook.GROUPER_ATTRIBUTE_AUTO_CREATE_MARKER_DEF;
2387         attributeAutoCreateDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
2388             attributeAutoCreateDefName, false, new QueryOptions().secondLevelCache(false));
2389         if (attributeAutoCreateDef == null) {
2390           attributeAutoCreateDef = attributeAutoCreateStem.addChildAttributeDef(AttributeAutoCreateHook.GROUPER_ATTRIBUTE_AUTO_CREATE_MARKER_DEF, 
2391               AttributeDefType.attr);
2392           attributeAutoCreateDef.setMultiAssignable(true);
2393           attributeAutoCreateDef.setAssignToAttributeDef(true);
2394           attributeAutoCreateDef.store();
2395         }
2396         
2397         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(attributeAutoCreateDef);
2398         
2399 
2400         //add a name
2401         attributeAutoCreateMarker = checkAttribute(attributeAutoCreateStem, attributeAutoCreateDef, 
2402             AttributeAutoCreateHook.GROUPER_ATTRIBUTE_AUTO_CREATE_MARKER, 
2403             "has autocreate settings settings", wasInCheckConfig);
2404         
2405         //lets add some rule attributes
2406         String attributeAutoCreateValueDefName = attributeAutoCreateStemName + ":" + AttributeAutoCreateHook.GROUPER_ATTRIBUTE_AUTO_CREATE_VALUE_DEF;
2407         AttributeDef attributeAutoCreateValueDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(  
2408             attributeAutoCreateValueDefName, false, new QueryOptions().secondLevelCache(false));
2409         
2410         if (attributeAutoCreateValueDef == null) {
2411           attributeAutoCreateValueDef = attributeAutoCreateStem.addChildAttributeDef(
2412               AttributeAutoCreateHook.GROUPER_ATTRIBUTE_AUTO_CREATE_VALUE_DEF, AttributeDefType.attr);
2413           attributeAutoCreateValueDef.setAssignToAttributeDefAssn(true);
2414           attributeAutoCreateValueDef.setValueType(AttributeDefValueType.string);
2415           attributeAutoCreateValueDef.store();
2416           autoAssignTheAutoAssignAttributes = true;
2417         }
2418 
2419         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(attributeAutoCreateValueDef);
2420 
2421         //the attributes can only be assigned to the type def
2422         // try an attribute def dependent on an attribute def name
2423         attributeAutoCreateValueDef.getAttributeDefScopeDelegate().assignOwnerNameEquals(attributeAutoCreateMarker.getName());
2424 
2425         //add some names
2426         autoAssignIfName = checkAttribute(attributeAutoCreateStem, attributeAutoCreateValueDef, AttributeAutoCreateHook.GROUPER_ATTRIBUTE_AUTO_CREATE_ATTR_IF_NAME, 
2427             "If an attribute is assigned with this name of attribute def name", wasInCheckConfig);
2428         autoAssignThenNames = checkAttribute(attributeAutoCreateStem, attributeAutoCreateValueDef, AttributeAutoCreateHook.GROUPER_ATTRIBUTE_AUTO_CREATE_ATTR_THEN_NAMES_ON_ASSIGN, 
2429             "Then assign these comma separated names of attribute def names to the assignment of the first name that was assigned", wasInCheckConfig);
2430         
2431         AttributeAutoCreateHook.registerHookIfNecessary();
2432 
2433       }
2434 
2435       {
2436         String notificationLastSentStemName = NotificationDaemon.attributeAutoCreateStemName();
2437 
2438         Stem notificationLastSentStem = StemFinder.findByName(grouperSession, notificationLastSentStemName, false, new QueryOptions().secondLevelCache(false));
2439         if (notificationLastSentStem == null) {
2440           notificationLastSentStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
2441             .assignDescription("folder for built in external subject invite attributes, and holds the data via attributes for invites.  Dont delete this folder")
2442             .assignName(notificationLastSentStemName).save();
2443         }
2444 
2445         //see if attributeDef is there
2446         String notificationLastSentDefName = notificationLastSentStemName + ":" + NotificationDaemon.GROUPER_ATTRIBUTE_NOTIFICATION_LAST_SENT_DEF;
2447 
2448         AttributeDef notificationLastSentDef = new AttributeDefSave(grouperSession).assignName(notificationLastSentDefName)
2449           .assignToImmMembership(true).assignMultiAssignable(false).assignMultiValued(false).assignValueType(AttributeDefValueType.string)
2450           .assignAttributeDefType(AttributeDefType.attr).assignCreateParentStemsIfNotExist(true).save();
2451 
2452         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(notificationLastSentDef);
2453 
2454         //add a name
2455         checkAttribute(notificationLastSentStem, notificationLastSentDef, 
2456             NotificationDaemon.GROUPER_ATTRIBUTE_NOTIFICATION_LAST_SENT, "yyyy/mm/dd.  Represents last date notification was sent", wasInCheckConfig);
2457       }
2458 
2459       {
2460         String externalSubjectStemName = ExternalSubjectAttrFramework.attributeExternalSubjectInviteStemName();
2461         
2462         Stem externalSubjectStem = StemFinder.findByName(grouperSession, externalSubjectStemName, false, new QueryOptions().secondLevelCache(false));
2463         if (externalSubjectStem == null) {
2464           externalSubjectStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
2465             .assignDescription("folder for built in external subject invite attributes, and holds the data via attributes for invites.  Dont delete this folder")
2466             .assignName(externalSubjectStemName).save();
2467         }
2468 
2469 
2470         //see if attributeDef is there
2471         String externalSubjectInviteDefName = externalSubjectStemName + ":externalSubjectInviteDef";
2472         
2473         AttributeDef externalSubjectInviteType = new AttributeDefSave(grouperSession).assignName(externalSubjectInviteDefName)
2474           .assignToStem(true).assignMultiAssignable(true).assignAttributeDefType(AttributeDefType.type).assignCreateParentStemsIfNotExist(true).save();
2475           
2476         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(externalSubjectInviteType);
2477         
2478         //add a name
2479         AttributeDefName externalSubjectInvite = checkAttribute(externalSubjectStem, externalSubjectInviteType, "externalSubjectInvite", "is an invite", wasInCheckConfig);
2480         
2481         //lets add some rule attributes
2482         String externalSubjectInviteAttrDefName = externalSubjectStemName + ":externalSubjectInviteAttrDef";
2483         AttributeDef externalSubjectInviteAttrType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
2484             externalSubjectInviteAttrDefName, false, new QueryOptions().secondLevelCache(false));
2485 
2486         if (externalSubjectInviteAttrType == null) {
2487           externalSubjectInviteAttrType = externalSubjectStem.addChildAttributeDef("externalSubjectInviteAttrDef", AttributeDefType.attr);
2488           externalSubjectInviteAttrType.setAssignToStemAssn(true);
2489           externalSubjectInviteAttrType.setValueType(AttributeDefValueType.string);
2490           externalSubjectInviteAttrType.store();
2491         }
2492 
2493         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(externalSubjectInviteAttrType);
2494         
2495 
2496         //the attributes can only be assigned to the type def
2497         // try an attribute def dependent on an attribute def name
2498         externalSubjectInviteAttrType.getAttributeDefScopeDelegate().assignOwnerNameEquals(externalSubjectInvite.getName());
2499 
2500         //add some names
2501         checkAttribute(externalSubjectStem, externalSubjectInviteAttrType, ExternalSubjectAttrFramework.EXTERNAL_SUBJECT_INVITE_EXPIRE_DATE, 
2502             "number of millis since 1970 when this invite expires", wasInCheckConfig);
2503         checkAttribute(externalSubjectStem, externalSubjectInviteAttrType, ExternalSubjectAttrFramework.EXTERNAL_SUBJECT_INVITE_DATE, 
2504             "number of millis since 1970 that this invite was issued", wasInCheckConfig);
2505         checkAttribute(externalSubjectStem, externalSubjectInviteAttrType, ExternalSubjectAttrFramework.EXTERNAL_SUBJECT_EMAIL_ADDRESS, 
2506             "email address this invite was sent to", wasInCheckConfig);
2507         checkAttribute(externalSubjectStem, externalSubjectInviteAttrType, ExternalSubjectAttrFramework.EXTERNAL_SUBJECT_INVITE_GROUP_UUIDS, 
2508             "comma separated group ids to assign this user to", wasInCheckConfig);
2509         checkAttribute(externalSubjectStem, externalSubjectInviteAttrType, ExternalSubjectAttrFramework.EXTERNAL_SUBJECT_INVITE_MEMBER_ID, 
2510             "member id who invited this user", wasInCheckConfig);
2511         checkAttribute(externalSubjectStem, externalSubjectInviteAttrType, ExternalSubjectAttrFramework.EXTERNAL_SUBJECT_INVITE_UUID, 
2512             "unique id in the email sent to the user", wasInCheckConfig);
2513         checkAttribute(externalSubjectStem, externalSubjectInviteAttrType, ExternalSubjectAttrFramework.EXTERNAL_SUBJECT_INVITE_EMAIL_WHEN_REGISTERED, 
2514             "email addresses to notify when the user registers", wasInCheckConfig);
2515         checkAttribute(externalSubjectStem, externalSubjectInviteAttrType, ExternalSubjectAttrFramework.EXTERNAL_SUBJECT_INVITE_EMAIL,
2516             "email sent to user as invite", wasInCheckConfig);      
2517       
2518       }      
2519 
2520       {
2521         String messagesRootStemName = GrouperBuiltinMessagingSystem.messageRootStemName();
2522 
2523         Stem messagesStem = StemFinder.findByName(grouperSession, messagesRootStemName, false, new QueryOptions().secondLevelCache(false));
2524         if (messagesStem == null) {
2525           messagesStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
2526             .assignDescription("folder for message queues and topics, topic to queue relationships and permissions")
2527             .assignName(messagesRootStemName)
2528             .save();
2529           if (wasInCheckConfig) {
2530             String error = "auto-created stem: " + messagesRootStemName;
2531             System.err.println("Grouper note: " + error);
2532             LOG.warn(error);
2533           }
2534         }
2535         
2536         {
2537           //see if role for permissions is there
2538           String grouperMessageNameOfRole = GrouperBuiltinMessagingSystem.grouperMessageNameOfRole();
2539           Group groupMessagingRoleGroup = GrouperDAOFactory.getFactory().getGroup().findByNameSecure(
2540               grouperMessageNameOfRole, false, new QueryOptions().secondLevelCache(false), GrouperUtil.toSet(TypeOfGroup.role));
2541           if (groupMessagingRoleGroup == null) {
2542             groupMessagingRoleGroup = (Group)messagesStem.addChildRole(GrouperUtil.extensionFromName(grouperMessageNameOfRole), 
2543                 GrouperUtil.extensionFromName(grouperMessageNameOfRole));
2544             if (wasInCheckConfig) {
2545               String error = "auto-created role: " + groupMessagingRoleGroup.getName();
2546               System.err.println("Grouper note: " + error);
2547               LOG.warn(error);
2548             }
2549           }
2550           GroupFinder.groupCacheAsRootAddSystemGroup(groupMessagingRoleGroup);
2551         }
2552 
2553         {
2554           //see if attributeDef for topics is there
2555           String grouperMessageTopicNameOfDef = GrouperBuiltinMessagingSystem.grouperMessageTopicNameOfDef();
2556           AttributeDef grouperMessageTopicDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
2557               grouperMessageTopicNameOfDef, false, new QueryOptions().secondLevelCache(false));
2558           if (grouperMessageTopicDef == null) {
2559             grouperMessageTopicDef = messagesStem.addChildAttributeDef(GrouperUtil.extensionFromName(grouperMessageTopicNameOfDef), AttributeDefType.perm);
2560             grouperMessageTopicDef.setAssignToGroup(true);
2561             grouperMessageTopicDef.setAssignToEffMembership(true);
2562             grouperMessageTopicDef.store();
2563             if (wasInCheckConfig) {
2564               String error = "auto-created attributeDef: " + grouperMessageTopicNameOfDef;
2565               System.err.println("Grouper note: " + error);
2566               LOG.warn(error);
2567             }
2568             
2569           }
2570           
2571           Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(grouperMessageTopicDef);
2572           
2573 
2574           grouperMessageTopicDef.getAttributeDefActionDelegate().configureActionList(GrouperBuiltinMessagingSystem.actionSendToTopic);
2575         }
2576 
2577         {
2578           //see if attributeDef for queues is there
2579           String grouperMessageQueueNameOfDef = GrouperBuiltinMessagingSystem.grouperMessageQueueNameOfDef();
2580           AttributeDef grouperMessageQueueDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
2581               grouperMessageQueueNameOfDef, false, new QueryOptions().secondLevelCache(false));
2582           if (grouperMessageQueueDef == null) {
2583             grouperMessageQueueDef = messagesStem.addChildAttributeDef(GrouperUtil.extensionFromName(grouperMessageQueueNameOfDef), AttributeDefType.perm);
2584             grouperMessageQueueDef.setAssignToGroup(true);
2585             grouperMessageQueueDef.setAssignToEffMembership(true);
2586             grouperMessageQueueDef.store();
2587             if (wasInCheckConfig) {
2588               String error = "auto-created attributeDef: " + grouperMessageQueueNameOfDef;
2589               System.err.println("Grouper note: " + error);
2590               LOG.warn(error);
2591             }
2592           }
2593           Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(grouperMessageQueueDef);
2594 
2595           grouperMessageQueueDef.getAttributeDefActionDelegate().configureActionList(
2596               GrouperBuiltinMessagingSystem.actionSendToQueue + "," + GrouperBuiltinMessagingSystem.actionReceive);
2597         }
2598 
2599         {
2600           String topicStemName = GrouperBuiltinMessagingSystem.topicStemName();
2601           Stem topicStem = StemFinder.findByName(grouperSession, topicStemName, false, new QueryOptions().secondLevelCache(false));
2602           if (topicStem == null) {
2603             topicStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
2604               .assignDescription("folder for message topics, add a permission here for a topic, imply queues by the topic")
2605               .assignName(topicStemName)
2606               .save();
2607             if (wasInCheckConfig) {
2608               String error = "auto-created stem: " + topicStemName;
2609               System.err.println("Grouper note: " + error);
2610               LOG.warn(error);
2611             }
2612           }
2613         }        
2614 
2615         {
2616           String queueStemName = GrouperBuiltinMessagingSystem.queueStemName();
2617           Stem queueStem = StemFinder.findByName(grouperSession, queueStemName, false);
2618           if (queueStem == null) {
2619             queueStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
2620               .assignDescription("folder for message queues, add a permission here for a queue, implied queues by the topic")
2621               .assignName(queueStemName)
2622               .save();
2623             if (wasInCheckConfig) {
2624               String error = "auto-created stem: " + queueStemName;
2625               System.err.println("Grouper note: " + error);
2626               LOG.warn(error);
2627             }
2628           }
2629         }        
2630 
2631       }
2632       {
2633         
2634         String attestationRootStemName = GrouperAttestationJob.attestationStemName();
2635         
2636         Stem attestationStem = StemFinder.findByName(grouperSession, attestationRootStemName, false);
2637         if (attestationStem == null) {
2638           attestationStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
2639             .assignDescription("folder for built in Grouper attestation attributes").assignName(attestationRootStemName)
2640             .save();
2641         }
2642 
2643         //see if attributeDef is there
2644         String attestationTypeDefName = attestationRootStemName + ":attestationDef";
2645         AttributeDef attestationType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
2646             attestationTypeDefName, false, new QueryOptions().secondLevelCache(false));
2647         if (attestationType == null) {
2648           attestationType = attestationStem.addChildAttributeDef("attestationDef", AttributeDefType.type);
2649           attestationType.setAssignToGroup(true);
2650           attestationType.setAssignToStem(true);
2651           attestationType.store();
2652         }
2653         
2654         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(attestationType);
2655         
2656 
2657         //add a name
2658         AttributeDefName attribute = checkAttribute(attestationStem, attestationType, "attestation", "has attestation attributes", wasInCheckConfig);
2659         
2660         //lets add some rule attributes
2661         String attestationAttrDefName = attestationRootStemName + ":attestationValueDef";
2662         AttributeDef attestationAttrType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(  
2663             attestationAttrDefName, false, new QueryOptions().secondLevelCache(false));
2664         if (attestationAttrType == null) {
2665           attestationAttrType = attestationStem.addChildAttributeDef("attestationValueDef", AttributeDefType.attr);
2666           attestationAttrType.setAssignToGroupAssn(true);
2667           attestationAttrType.setAssignToStemAssn(true);
2668           attestationAttrType.setValueType(AttributeDefValueType.string);
2669           attestationAttrType.store();
2670         }
2671 
2672         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(attestationAttrType);
2673 
2674         //the attributes can only be assigned to the type def
2675         // try an attribute def dependent on an attribute def name
2676         attestationAttrType.getAttributeDefScopeDelegate().assignOwnerNameEquals(attribute.getName());
2677 
2678         //add some names
2679         checkAttribute(attestationStem, attestationAttrType, GrouperAttestationJob.ATTESTATION_DATE_CERTIFIED, 
2680             "Last certified date for this group", wasInCheckConfig);
2681         checkAttribute(attestationStem, attestationAttrType, GrouperAttestationJob.ATTESTATION_DAYS_BEFORE_TO_REMIND,
2682             "Number of days before attestation deadline to start sending emails about it to owners", wasInCheckConfig);
2683         checkAttribute(attestationStem, attestationAttrType, GrouperAttestationJob.ATTESTATION_DAYS_UNTIL_RECERTIFY,
2684             "Number of days until need to recertify from last certification", wasInCheckConfig);
2685         checkAttribute(attestationStem, attestationAttrType, GrouperAttestationJob.ATTESTATION_DIRECT_ASSIGNMENT,
2686             "If this group has attestation settings and not inheriting from ancestor folders (group only)", wasInCheckConfig);
2687         checkAttribute(attestationStem, attestationAttrType, GrouperAttestationJob.ATTESTATION_EMAIL_ADDRESSES,
2688             "Comma separated email addresses to send reminders to, if blank then send to group admins", wasInCheckConfig);
2689         checkAttribute(attestationStem, attestationAttrType, GrouperAttestationJob.ATTESTATION_LAST_EMAILED_DATE,
2690             "yyyy/mm/dd date that this was last emailed so multiple emails don't go out on same day (group only)", wasInCheckConfig);
2691         checkAttribute(attestationStem, attestationAttrType, GrouperAttestationJob.ATTESTATION_MIN_CERTIFIED_DATE,
2692             "yyyy/mm/dd date that folder set certification now. Any groups in this folder will have this date at a minimum of last certified date.", wasInCheckConfig);
2693         checkAttribute(attestationStem, attestationAttrType, GrouperAttestationJob.ATTESTATION_CALCULATED_DAYS_LEFT,
2694             "In order to search for attestations, this is the calculated days left before needs attestation", wasInCheckConfig);
2695         checkAttribute(attestationStem, attestationAttrType, GrouperAttestationJob.ATTESTATION_SEND_EMAIL,
2696             "true or false if emails should be sent", wasInCheckConfig);
2697         checkAttribute(attestationStem, attestationAttrType, GrouperAttestationJob.ATTESTATION_STEM_SCOPE,
2698             "one or sub for if attestation settings inherit to just this folder or also to subfolders (folder only)", wasInCheckConfig);
2699         checkAttribute(attestationStem, attestationAttrType, GrouperAttestationJob.ATTESTATION_HAS_ATTESTATION,
2700             "If this folder has attestation directly assigned or if this group has attestation either directly or indirectly assigned", wasInCheckConfig);
2701         checkAttribute(attestationStem, attestationAttrType, GrouperAttestationJob.ATTESTATION_TYPE,
2702             "Type of attestation.  Either based on groups or a report.", wasInCheckConfig);
2703         checkAttribute(attestationStem, attestationAttrType, GrouperAttestationJob.ATTESTATION_REPORT_CONFIGURATION_ID,
2704             "The report configuration associated with this attestation if any", wasInCheckConfig);
2705         checkAttribute(attestationStem, attestationAttrType, GrouperAttestationJob.ATTESTATION_AUTHORIZED_GROUP_ID,
2706             "The authorized group associated with this attestation if any", wasInCheckConfig);
2707         checkAttribute(attestationStem, attestationAttrType, GrouperAttestationJob.ATTESTATION_EMAIL_GROUP_ID,
2708             "Email attestation reminders for group attestation to this group", wasInCheckConfig);
2709       }
2710 
2711       {
2712         
2713         String customUiRootStemName = CustomUiAttributeNames.customUiStemName();
2714         
2715         Stem customUiStem = StemFinder.findByName(grouperSession, customUiRootStemName, false);
2716         if (customUiStem == null) {
2717           customUiStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
2718             .assignDescription("folder for Grouper custom UI attributes").assignName(customUiRootStemName)
2719             .save();
2720         }
2721 
2722         //see if attributeDef is there
2723         String customUiTypeDefName = customUiRootStemName + ":" + CustomUiAttributeNames.CUSTOM_UI_DEF;
2724 
2725         AttributeDef customUiType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
2726             customUiTypeDefName, false, new QueryOptions().secondLevelCache(false));
2727         if (customUiType == null) {
2728           customUiType = customUiStem.addChildAttributeDef(CustomUiAttributeNames.CUSTOM_UI_DEF, AttributeDefType.type);
2729           customUiType.setAssignToGroup(true);
2730           customUiType.store();
2731         }
2732         
2733         //add a name
2734         AttributeDefName attribute = checkAttribute(customUiStem, customUiType, CustomUiAttributeNames.CUSTOM_UI_MARKER, "has custom UI attributes", wasInCheckConfig);
2735         
2736         //lets add some rule attributes
2737         String customUiAttrDefName = customUiRootStemName + ":" + CustomUiAttributeNames.CUSTOM_UI_VALUE_DEF;
2738         AttributeDef customUiAttrType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(  
2739             customUiAttrDefName, false, new QueryOptions().secondLevelCache(false));
2740         if (customUiAttrType == null) {
2741           customUiAttrType = customUiStem.addChildAttributeDef(CustomUiAttributeNames.CUSTOM_UI_VALUE_DEF, AttributeDefType.attr);
2742           customUiAttrType.setAssignToGroupAssn(true);
2743           customUiAttrType.setMultiValued(true);
2744           customUiAttrType.setValueType(AttributeDefValueType.string);
2745           customUiAttrType.store();
2746         }
2747 
2748         //the attributes can only be assigned to the type def
2749         // try an attribute def dependent on an attribute def name
2750         customUiAttrType.getAttributeDefScopeDelegate().assignOwnerNameEquals(attribute.getName());
2751 
2752         //add some names
2753         checkAttribute(customUiStem, customUiAttrType, CustomUiAttributeNames.CUSTOM_UI_TEXT_CONFIG_BEANS, 
2754             "JSONs of CustomUiTextConfigBeans.  Add a json with multiple values to configure text for this custom UI", wasInCheckConfig);
2755         checkAttribute(customUiStem, customUiAttrType, CustomUiAttributeNames.CUSTOM_UI_USER_QUERY_CONFIG_BEANS, 
2756             "JSONs of CustomUiUserQueryConfigBeans.  Add a json with multiple values to configure variables and queries for this custom UI", wasInCheckConfig);
2757       }
2758 
2759       // add attribute defs for grouper types
2760       {
2761         String grouperObjectTypesRootStemName = GrouperObjectTypesSettings.objectTypesStemName();
2762         
2763         Stem grouperTypesStemName = StemFinder.findByName(grouperSession, grouperObjectTypesRootStemName, false);
2764         if (grouperTypesStemName == null) {
2765           grouperTypesStemName = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
2766             .assignDescription("folder for built in Grouper types objects").assignName(grouperObjectTypesRootStemName)
2767             .save();
2768         }
2769 
2770         //see if attributeDef is there
2771         String grouperObjectTypeDefName = grouperObjectTypesRootStemName + ":" + GrouperObjectTypesAttributeNames.GROUPER_OBJECT_TYPE_DEF;
2772         AttributeDef grouperObjectType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
2773             grouperObjectTypeDefName, false, new QueryOptions().secondLevelCache(false));
2774         if (grouperObjectType == null) {
2775           grouperObjectType = grouperTypesStemName.addChildAttributeDef(GrouperObjectTypesAttributeNames.GROUPER_OBJECT_TYPE_DEF, AttributeDefType.type);
2776           //assign once for each affiliation
2777           grouperObjectType.setMultiAssignable(true);
2778           grouperObjectType.setAssignToGroup(true);
2779           grouperObjectType.setAssignToStem(true);
2780           grouperObjectType.store();
2781         }
2782         
2783         //add a name
2784         AttributeDefName attribute = checkAttribute(grouperTypesStemName, grouperObjectType, GrouperObjectTypesAttributeNames.GROUPER_OBJECT_TYPE_ATTRIBUTE_NAME, "has grouper object type attributes", wasInCheckConfig);
2785         
2786         //lets add some rule attributes
2787         String grouperObjectTypeAttrDefName = grouperObjectTypesRootStemName + ":" + GrouperObjectTypesAttributeNames.GROUPER_OBJECT_TYPE_VALUE_DEF;
2788         AttributeDef grouperObjectTypeAttrType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(  
2789             grouperObjectTypeAttrDefName, false, new QueryOptions().secondLevelCache(false));
2790         if (grouperObjectTypeAttrType == null) {
2791           grouperObjectTypeAttrType = grouperTypesStemName.addChildAttributeDef(GrouperObjectTypesAttributeNames.GROUPER_OBJECT_TYPE_VALUE_DEF, AttributeDefType.attr);
2792           grouperObjectTypeAttrType.setAssignToGroupAssn(true);
2793           grouperObjectTypeAttrType.setAssignToStemAssn(true);
2794           grouperObjectTypeAttrType.setAssignToAttributeDefAssn(true);
2795           grouperObjectTypeAttrType.setValueType(AttributeDefValueType.string);
2796           grouperObjectTypeAttrType.store();
2797         }
2798 
2799         //the attributes can only be assigned to the type def
2800         // try an attribute def dependent on an attribute def name
2801         grouperObjectTypeAttrType.getAttributeDefScopeDelegate().assignOwnerNameEquals(attribute.getName());
2802         
2803         checkAttribute(grouperTypesStemName, grouperObjectTypeAttrType, GrouperObjectTypesAttributeNames.GROUPER_OBJECT_TYPE_NAME,
2804             "ref, basis, policy,etc, bundle, org, test, service, app, readOnly, grouperSecurity", wasInCheckConfig);
2805         
2806         checkAttribute(grouperTypesStemName, grouperObjectTypeAttrType, GrouperObjectTypesAttributeNames.GROUPER_OBJECT_TYPE_DATA_OWNER, 
2807             "e.g. Registrar's office owns this data", wasInCheckConfig);
2808         
2809         checkAttribute(grouperTypesStemName, grouperObjectTypeAttrType, GrouperObjectTypesAttributeNames.GROUPER_OBJECT_TYPE_MEMBERS_DESCRIPTION, 
2810             "Human readable description of the members of this group", wasInCheckConfig);
2811         
2812         checkAttribute(grouperTypesStemName, grouperObjectTypeAttrType, GrouperObjectTypesAttributeNames.GROUPER_OBJECT_TYPE_DIRECT_ASSIGNMENT, 
2813             "if configuration is directly assigned to the group or folder or inherited from parent", wasInCheckConfig);
2814         
2815         checkAttribute(grouperTypesStemName, grouperObjectTypeAttrType, GrouperObjectTypesAttributeNames.GROUPER_OBJECT_TYPE_SERVICE_NAME, 
2816             "name of the service that this app falls under", wasInCheckConfig);
2817         
2818         checkAttribute(grouperTypesStemName, grouperObjectTypeAttrType, GrouperObjectTypesAttributeNames.GROUPER_OBJECT_TYPE_OWNER_STEM_ID, 
2819             "Stem ID of the folder where the configuration is inherited from.  This is blank if this is a direct assignment and not inherited", wasInCheckConfig);
2820 
2821       }
2822       
2823       {
2824         // add workflow config attributes
2825         String workflowRootStemName = GrouperWorkflowSettings.workflowStemName();
2826         
2827         Stem workflowStem = StemFinder.findByName(grouperSession, workflowRootStemName, false);
2828         if (workflowStem == null) {
2829           workflowStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
2830             .assignDescription("folder for built in Grouper workflow attributes").assignName(workflowRootStemName)
2831             .save();
2832         }
2833           //see if attributeDef is there
2834 
2835           String workflowTypeDefName = workflowRootStemName + ":" + GROUPER_WORKFLOW_CONFIG_DEF;
2836           AttributeDef workflowType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
2837               workflowTypeDefName, false, new QueryOptions().secondLevelCache(false));
2838           if (workflowType == null) {
2839             workflowType = workflowStem.addChildAttributeDef(GROUPER_WORKFLOW_CONFIG_DEF, AttributeDefType.type);
2840             workflowType.setMultiAssignable(true);
2841             workflowType.setAssignToGroup(true);
2842             workflowType.store();
2843           }
2844           
2845           Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(workflowType);
2846           
2847 
2848           //add a name
2849           AttributeDefName attribute = checkAttribute(workflowStem, workflowType, GROUPER_WORKFLOW_CONFIG_ATTRIBUTE_NAME, "has workflow approval attributes", wasInCheckConfig);
2850           
2851           //add attributes
2852           String workflowAttrDefName = workflowRootStemName + ":" + GROUPER_WORKFLOW_CONFIG_VALUE_DEF;
2853           AttributeDef workflowAttrType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(  
2854               workflowAttrDefName, false, new QueryOptions().secondLevelCache(false));
2855           if (workflowAttrType == null) {
2856             workflowAttrType = workflowStem.addChildAttributeDef(GROUPER_WORKFLOW_CONFIG_VALUE_DEF, AttributeDefType.attr);
2857             workflowAttrType.setAssignToGroupAssn(true);
2858             workflowAttrType.setValueType(AttributeDefValueType.string);
2859             workflowAttrType.store();
2860           }
2861 
2862           Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(workflowAttrType);
2863 
2864           //the attributes can only be assigned to the type def
2865           // try an attribute def dependent on an attribute def name
2866           workflowAttrType.getAttributeDefScopeDelegate().assignOwnerNameEquals(attribute.getName());
2867 
2868           //add some names
2869           checkAttribute(workflowStem, workflowAttrType, GROUPER_WORKFLOW_CONFIG_TYPE, 
2870               "workflow implementation type. default is grouper", wasInCheckConfig);
2871           checkAttribute(workflowStem, workflowAttrType, GROUPER_WORKFLOW_CONFIG_APPROVALS,
2872               "JSON config of the workflow approvals", wasInCheckConfig);
2873           checkAttribute(workflowStem, workflowAttrType, GROUPER_WORKFLOW_CONFIG_NAME,
2874               "Name of workflow.", wasInCheckConfig);
2875           checkAttribute(workflowStem, workflowAttrType, GROUPER_WORKFLOW_CONFIG_ID,
2876               "Camel-case alphanumeric id of workflow", wasInCheckConfig);
2877           checkAttribute(workflowStem, workflowAttrType, GROUPER_WORKFLOW_CONFIG_DESCRIPTION,
2878               "workflow config description", wasInCheckConfig);
2879           checkAttribute(workflowStem, workflowAttrType, GROUPER_WORKFLOW_CONFIG_PARAMS,
2880               "workflow config params", wasInCheckConfig);
2881           checkAttribute(workflowStem, workflowAttrType, GROUPER_WORKFLOW_CONFIG_FORM,
2882               "workflow form with html, javascript", wasInCheckConfig);
2883           checkAttribute(workflowStem, workflowAttrType, GROUPER_WORKFLOW_CONFIG_VIEWERS_GROUP_ID,
2884               "GroupId of people who can view this workflow and instances of this workflow.", wasInCheckConfig);
2885           checkAttribute(workflowStem, workflowAttrType, GROUPER_WORKFLOW_CONFIG_SEND_EMAIL,
2886               "true/false if email should be sent", wasInCheckConfig);
2887           checkAttribute(workflowStem, workflowAttrType, GROUPER_WORKFLOW_CONFIG_ENABLED,
2888               "Could by true, false, or noNewSubmissions", wasInCheckConfig);
2889           
2890           // add workflow instance attributes
2891           String grouperWorkflowInstanceDefName = workflowRootStemName + ":" + GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_DEF;
2892           AttributeDef grouperWorkflowInstance = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
2893               grouperWorkflowInstanceDefName, false, new QueryOptions().secondLevelCache(false));
2894           if (grouperWorkflowInstance == null) {
2895             grouperWorkflowInstance = workflowStem.addChildAttributeDef(GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_DEF, AttributeDefType.type);
2896             grouperWorkflowInstance.setMultiAssignable(true);
2897             grouperWorkflowInstance.setAssignToGroup(true);
2898             grouperWorkflowInstance.store();
2899           }
2900           
2901           //add a name
2902           AttributeDefName instanceAttribute = checkAttribute(workflowStem, grouperWorkflowInstance, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_ATTRIBUTE_NAME, "has grouper workflow instance attributes", wasInCheckConfig);
2903           
2904           //lets add some attributes names
2905           String grouperWorkflowInstanceAttrDefName = workflowRootStemName + ":" + GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_VALUE_DEF;
2906           AttributeDef grouperWorkflowInstanceAttrType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(  
2907               grouperWorkflowInstanceAttrDefName, false, new QueryOptions().secondLevelCache(false));
2908           if (grouperWorkflowInstanceAttrType == null) {
2909             grouperWorkflowInstanceAttrType = workflowStem.addChildAttributeDef(GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_VALUE_DEF, AttributeDefType.attr);
2910             grouperWorkflowInstanceAttrType.setAssignToGroupAssn(true);
2911             grouperWorkflowInstanceAttrType.setValueType(AttributeDefValueType.string);
2912             grouperWorkflowInstanceAttrType.store();
2913           }
2914 
2915           //the attributes can only be assigned to the type def
2916           // try an attribute def dependent on an attribute def name
2917           grouperWorkflowInstanceAttrType.getAttributeDefScopeDelegate().assignOwnerNameEquals(instanceAttribute.getName());
2918           
2919           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_STATE,
2920               "Any of the states, plus exception", wasInCheckConfig);
2921           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_LAST_UPDATED_MILLIS_SINCE_1970,
2922               "number of millis since 1970 when this instance was last updated", wasInCheckConfig);
2923           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_CONFIG_MARKER_ASSIGNMENT_ID,
2924               "Attribute assign ID of the marker attribute of the config", wasInCheckConfig);
2925           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_INITIATED_MILLIS_SINCE_1970,
2926               "millis since 1970 that this workflow was submitted", wasInCheckConfig);
2927           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_UUID,
2928               "uuid assigned to this workflow instance", wasInCheckConfig);
2929           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_FILE_INFO,
2930               "workflow instance file info", wasInCheckConfig);
2931           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_ENCRYPTION_KEY,
2932               "randomly generated 16 char alphanumeric encryption key", wasInCheckConfig);
2933           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_LAST_EMAILED_DATE,
2934               "yyyy/mm/dd date that this was last emailed", wasInCheckConfig);
2935           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_LAST_EMAILED_STATE,
2936               "the state of the workflow instance when it was last emailed", wasInCheckConfig);
2937           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_LOG,
2938               "has brief info about who did what when on this instance", wasInCheckConfig);
2939           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_ERROR,
2940               "error message including stack of why this instance is in exception state", wasInCheckConfig);
2941           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_PARAM_VALUE_0,
2942               "param value 0", wasInCheckConfig);
2943           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_PARAM_VALUE_1,
2944               "param value 1", wasInCheckConfig);
2945           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_PARAM_VALUE_2,
2946               "param value 2", wasInCheckConfig);
2947           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_PARAM_VALUE_3,
2948               "param value 3", wasInCheckConfig);
2949           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_PARAM_VALUE_4,
2950               "param value 4", wasInCheckConfig);
2951           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_PARAM_VALUE_5,
2952               "param value 5", wasInCheckConfig);
2953           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_PARAM_VALUE_6,
2954               "param value 6", wasInCheckConfig);
2955           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_PARAM_VALUE_7,
2956               "param value 7", wasInCheckConfig);
2957           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_PARAM_VALUE_8,
2958               "param value 8", wasInCheckConfig);
2959           checkAttribute(workflowStem, grouperWorkflowInstanceAttrType, GrouperWorkflowInstanceAttributeNames.GROUPER_WORKFLOW_INSTANCE_PARAM_VALUE_9,
2960               "param value 9", wasInCheckConfig);
2961             
2962         }
2963       
2964 
2965       {
2966         // add attribute defs for grouper report config and grouper report instance
2967         String reportConfigStemName = GrouperReportSettings.reportConfigStemName();
2968         
2969         Stem reportConfigStem = StemFinder.findByName(grouperSession, reportConfigStemName, false);
2970         if (reportConfigStem == null) {
2971           reportConfigStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
2972             .assignDescription("folder for Grouper report config").assignName(reportConfigStemName)
2973             .save();
2974         }
2975 
2976         String grouperReportConfigDefName = reportConfigStemName + ":" + GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_DEF;
2977         AttributeDef grouperReportConfig = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
2978             grouperReportConfigDefName, false, new QueryOptions().secondLevelCache(false));
2979         if (grouperReportConfig == null) {
2980           grouperReportConfig = reportConfigStem.addChildAttributeDef(GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_DEF, AttributeDefType.type);
2981           //assign once for each affiliation
2982           grouperReportConfig.setMultiAssignable(true);
2983           grouperReportConfig.setAssignToGroup(true);
2984           grouperReportConfig.setAssignToStem(true);
2985           grouperReportConfig.store();
2986         }
2987         
2988         //add a name
2989         AttributeDefName attribute = checkAttribute(reportConfigStem, grouperReportConfig, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_ATTRIBUTE_NAME, "has grouper report config attributes", wasInCheckConfig);
2990         
2991         //lets add some attributes names
2992         String grouperReportConfigAttrDefName = reportConfigStemName + ":" + GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_VALUE_DEF;
2993         AttributeDef grouperReportConfigAttrType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(  
2994             grouperReportConfigAttrDefName, false, new QueryOptions().secondLevelCache(false));
2995         if (grouperReportConfigAttrType == null) {
2996           grouperReportConfigAttrType = reportConfigStem.addChildAttributeDef(GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_VALUE_DEF, AttributeDefType.attr);
2997           grouperReportConfigAttrType.setAssignToGroupAssn(true);
2998           grouperReportConfigAttrType.setAssignToStemAssn(true);
2999           grouperReportConfigAttrType.setValueType(AttributeDefValueType.string);
3000           grouperReportConfigAttrType.store();
3001         }
3002 
3003         //the attributes can only be assigned to the type def
3004         // try an attribute def dependent on an attribute def name
3005         grouperReportConfigAttrType.getAttributeDefScopeDelegate().assignOwnerNameEquals(attribute.getName());
3006         
3007         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_TYPE,
3008             "report config type. Currently only SQL is available", wasInCheckConfig);
3009         
3010         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_FORMAT, 
3011             "report config format. Currently only CSV is available", wasInCheckConfig);
3012         
3013         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_NAME, 
3014             "Name of report. No two reports in the same owner should have the same name", wasInCheckConfig);
3015         
3016         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_FILE_NAME, 
3017             "file name in which report contents will be saved", wasInCheckConfig);
3018         
3019         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_DESCRIPTION, 
3020             "Textarea which describes the information in the report. Must be less than 4k", wasInCheckConfig);
3021         
3022         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_VIEWERS_GROUP_ID, 
3023             "GroupId of people who can view this report. Grouper admins can view any report", wasInCheckConfig);
3024         
3025         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_QUARTZ_CRON, 
3026             "Quartz cron-like schedule", wasInCheckConfig);
3027         
3028         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_SEND_EMAIL_WITH_NO_DATA, 
3029             "Set to false if email should not be sent if the report has no data", wasInCheckConfig);
3030         
3031         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_STORE_WITH_NO_DATA, 
3032             "Set to false if report should not be stored if the report has no data", wasInCheckConfig);
3033         
3034         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_SEND_EMAIL, 
3035             "true/false if email should be sent", wasInCheckConfig);
3036         
3037         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_EMAIL_SUBJECT, 
3038             "subject for email (optional, will be generated from report name if blank)", wasInCheckConfig);
3039         
3040         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_EMAIL_BODY, 
3041             "email body", wasInCheckConfig);
3042         
3043         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_SEND_EMAIL_TO_VIEWERS, 
3044             "true/false if report viewers should get email (if reportSendEmail is true)", wasInCheckConfig);
3045         
3046         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_SEND_EMAIL_TO_GROUP_ID, 
3047             "this is the groupId where members are retrieved from, and the subject email attribute, if not null then send", wasInCheckConfig);
3048         
3049         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_QUERY, 
3050             "SQL for the report. The columns must be named in the SQL (e.g. not select *) and generally this comes from a view", wasInCheckConfig);
3051         
3052         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_SCRIPT, 
3053             "GSH script for the report.  Put report file in: gsh_builtin_gshReportRuntime.getGrouperReportData().getFile()", wasInCheckConfig);
3054         
3055         checkAttribute(reportConfigStem, grouperReportConfigAttrType, GrouperReportConfigAttributeNames.GROUPER_REPORT_CONFIG_ENABLED, 
3056             "logic from loader enabled, either enable or disabled this job", wasInCheckConfig);
3057         
3058 
3059         //see if attributeDef is there
3060         String grouperReportInstanceDefName = reportConfigStemName + ":" + GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_DEF;
3061         AttributeDef grouperReportInstance = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3062             grouperReportInstanceDefName, false, new QueryOptions().secondLevelCache(false));
3063         if (grouperReportInstance == null) {
3064           grouperReportInstance = reportConfigStem.addChildAttributeDef(GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_DEF, AttributeDefType.type);
3065           //assign once for each affiliation
3066           grouperReportInstance.setMultiAssignable(true);
3067           grouperReportInstance.setAssignToGroup(true);
3068           grouperReportInstance.setAssignToStem(true);
3069           grouperReportInstance.store();
3070         }
3071         
3072         //add a name
3073         AttributeDefName instanceAttribute = checkAttribute(reportConfigStem, grouperReportInstance, GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_ATTRIBUTE_NAME, "has grouper report instance attributes", wasInCheckConfig);
3074         
3075         //lets add some attributes names
3076         String grouperReportInstanceAttrDefName = reportConfigStemName + ":" + GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_VALUE_DEF;
3077         AttributeDef grouperReportInstanceAttrType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(  
3078             grouperReportInstanceAttrDefName, false, new QueryOptions().secondLevelCache(false));
3079         if (grouperReportInstanceAttrType == null) {
3080           grouperReportInstanceAttrType = reportConfigStem.addChildAttributeDef(GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_VALUE_DEF, AttributeDefType.attr);
3081           grouperReportInstanceAttrType.setAssignToGroupAssn(true);
3082           grouperReportInstanceAttrType.setAssignToStemAssn(true);
3083           grouperReportInstanceAttrType.setValueType(AttributeDefValueType.string);
3084           grouperReportInstanceAttrType.store();
3085         }
3086 
3087         //the attributes can only be assigned to the type def
3088         // try an attribute def dependent on an attribute def name
3089         grouperReportInstanceAttrType.getAttributeDefScopeDelegate().assignOwnerNameEquals(instanceAttribute.getName());
3090         
3091         checkAttribute(reportConfigStem, grouperReportInstanceAttrType, GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_STATUS,
3092             "SUCCESS means link to the report from screen, ERROR means didnt execute successfully", wasInCheckConfig);
3093         
3094         checkAttribute(reportConfigStem, grouperReportInstanceAttrType, GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_MILLIS_ELAPSED, 
3095             "number of millis it took to generate this report", wasInCheckConfig);
3096         
3097         checkAttribute(reportConfigStem, grouperReportInstanceAttrType, GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_CONFIG_MARKER_ASSIGNMENT_ID, 
3098             "Attribute assign ID of the marker attribute of the config (same owner as this attribute, but there could be many reports configured on one owner)", wasInCheckConfig);
3099         
3100         checkAttribute(reportConfigStem, grouperReportInstanceAttrType, GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_MILLIS_SINCE_1970, 
3101             "millis since 1970 that this report was run. This must match the timestamp in the report name and storage", wasInCheckConfig);
3102         
3103         checkAttribute(reportConfigStem, grouperReportInstanceAttrType, GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_SIZE_BYTES, 
3104             "number of bytes of the unencrypted report", wasInCheckConfig);
3105         
3106         checkAttribute(reportConfigStem, grouperReportInstanceAttrType, GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_FILE_NAME, 
3107             "filename of report", wasInCheckConfig);
3108         
3109         checkAttribute(reportConfigStem, grouperReportInstanceAttrType, GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_FILE_POINTER, 
3110             "depending on storage type, this is a pointer to the report in storage, e.g. the S3 address. note the S3 address is .csv suffix, but change to __metadata.json for instance metadata", wasInCheckConfig);
3111         
3112         checkAttribute(reportConfigStem, grouperReportInstanceAttrType, GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_DOWNLOAD_COUNT, 
3113             "number of times this report was downloaded (note update this in try/catch and a for loop so concurrency doesnt cause problems)", wasInCheckConfig);
3114         
3115         checkAttribute(reportConfigStem, grouperReportInstanceAttrType, GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_ENCRYPTION_KEY, 
3116             "randomly generated 16 char alphanumeric encryption key (never allow display or edit of this)", wasInCheckConfig);
3117         
3118         checkAttribute(reportConfigStem, grouperReportInstanceAttrType, GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_ROWS, 
3119             "number of rows returned in report", wasInCheckConfig);
3120         
3121         checkAttribute(reportConfigStem, grouperReportInstanceAttrType, GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_EMAIL_TO_SUBJECTS, 
3122             "source::::subjectId1, source2::::subjectId2 list for subjects who were were emailed successfully (cant be more than 4k chars)", wasInCheckConfig);
3123         
3124         checkAttribute(reportConfigStem, grouperReportInstanceAttrType, GrouperReportInstanceAttributeNames.GROUPER_REPORT_INSTANCE_EMAIL_TO_SUBJECTS_ERROR, 
3125             "source::::subjectId1, source2::::subjectId2 list for subjects who were were NOT emailed successfully, dont include g:gsa groups (cant be more than 4k chars)", wasInCheckConfig);
3126       }
3127       
3128       {
3129         
3130         Stem loaderMetadataStem = StemFinder.findByName(grouperSession, loaderMetadataStemName(), false, new QueryOptions().secondLevelCache(false));
3131         if (loaderMetadataStem == null) {
3132           loaderMetadataStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
3133             .assignDescription("folder for built in Grouper Loader Metadata attributes").assignName(loaderMetadataStemName())
3134             .save();
3135         }
3136 
3137         //see if attributeDef is there
3138         String loaderMetadataTypeDefName = loaderMetadataStemName() + ":loaderMetadataDef";
3139         AttributeDef loaderMetadataType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3140             loaderMetadataTypeDefName, false, new QueryOptions().secondLevelCache(false));
3141         if (loaderMetadataType == null) {
3142           loaderMetadataType = loaderMetadataStem.addChildAttributeDef("loaderMetadataDef", AttributeDefType.type);
3143           loaderMetadataType.setAssignToGroup(true);
3144           loaderMetadataType.store();
3145         }
3146         
3147         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(loaderMetadataType);
3148 
3149         //add a name
3150         AttributeDefName attribute = checkAttribute(loaderMetadataStem, loaderMetadataType, "loaderMetadata", "has metadata attributes", wasInCheckConfig);
3151         
3152         //lets add some rule attributes
3153         String loaderMetadataAttrDefName = loaderMetadataStemName() + ":loaderMetadataValueDef";
3154         AttributeDef loaderMetadataAttrType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(  
3155             loaderMetadataAttrDefName, false, new QueryOptions().secondLevelCache(false));
3156         if (loaderMetadataAttrType == null) {
3157           loaderMetadataAttrType = loaderMetadataStem.addChildAttributeDef("loaderMetadataValueDef", AttributeDefType.attr);
3158           loaderMetadataAttrType.setAssignToGroupAssn(true);
3159           loaderMetadataAttrType.setValueType(AttributeDefValueType.string);
3160           loaderMetadataAttrType.store();
3161         }
3162 
3163         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(loaderMetadataAttrType);
3164 
3165         //the attributes can only be assigned to the type def
3166         // try an attribute def dependent on an attribute def name
3167         loaderMetadataAttrType.getAttributeDefScopeDelegate().assignOwnerNameEquals(attribute.getName());
3168 
3169         //add some names
3170         checkAttribute(loaderMetadataStem, loaderMetadataAttrType, GrouperLoader.ATTRIBUTE_GROUPER_LOADER_METADATA_LOADED, 
3171             "True means the group was loaded from loader", wasInCheckConfig);
3172         checkAttribute(loaderMetadataStem, loaderMetadataAttrType, GrouperLoader.ATTRIBUTE_GROUPER_LOADER_METADATA_GROUP_ID,
3173             "Group id which is being populated from the loader", wasInCheckConfig);
3174         checkAttribute(loaderMetadataStem, loaderMetadataAttrType, GrouperLoader.ATTRIBUTE_GROUPER_LOADER_METADATA_LAST_FULL_MILLIS,
3175             "Millis since 1970 that this group was fully processed", wasInCheckConfig);
3176         checkAttribute(loaderMetadataStem, loaderMetadataAttrType, GrouperLoader.ATTRIBUTE_GROUPER_LOADER_METADATA_LAST_INCREMENTAL_MILLIS,
3177             "Millis since 1970 that this group was incrementally processed", wasInCheckConfig);
3178         checkAttribute(loaderMetadataStem, loaderMetadataAttrType, GrouperLoader.ATTRIBUTE_GROUPER_LOADER_METADATA_LAST_SUMMARY,
3179             "Summary of loader job", wasInCheckConfig);
3180       }
3181       
3182       {
3183         String rulesRootStemName = RuleUtils.attributeRuleStemName();
3184         
3185         Stem rulesStem = StemFinder.findByName(grouperSession, rulesRootStemName, false, new QueryOptions().secondLevelCache(false));
3186         if (rulesStem == null) {
3187           rulesStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
3188             .assignDescription("folder for built in Grouper rules attributes").assignName(rulesRootStemName)
3189             .save();
3190         }
3191 
3192         //see if attributeDef is there
3193         String ruleTypeDefName = rulesRootStemName + ":rulesTypeDef";
3194         AttributeDef ruleType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3195             ruleTypeDefName, false, new QueryOptions().secondLevelCache(false));
3196         if (ruleType == null) {
3197           ruleType = rulesStem.addChildAttributeDef("rulesTypeDef", AttributeDefType.type);
3198           ruleType.setAssignToGroup(true);
3199           ruleType.setAssignToStem(true);
3200           ruleType.setAssignToAttributeDef(true);
3201           ruleType.setMultiAssignable(true);
3202           ruleType.store();
3203         }
3204         
3205         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(ruleType);
3206 
3207         //add a name
3208         AttributeDefName rule = checkAttribute(rulesStem, ruleType, "rule", "is a rule", wasInCheckConfig);
3209         
3210         //lets add some rule attributes
3211         String ruleAttrDefName = rulesRootStemName + ":rulesAttrDef";
3212         AttributeDef ruleAttrType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(  
3213             ruleAttrDefName, false, new QueryOptions().secondLevelCache(false));
3214         if (ruleAttrType == null) {
3215           ruleAttrType = rulesStem.addChildAttributeDef("rulesAttrDef", AttributeDefType.attr);
3216           ruleAttrType.setAssignToGroupAssn(true);
3217           ruleAttrType.setAssignToAttributeDefAssn(true);
3218           ruleAttrType.setAssignToStemAssn(true);
3219           ruleAttrType.setValueType(AttributeDefValueType.string);
3220           ruleAttrType.store();
3221         }
3222 
3223         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(ruleAttrType);
3224 
3225         //if not configured properly, configure it properly
3226         if (!ruleAttrType.isAssignToAttributeDefAssn()) {
3227           ruleAttrType.setAssignToAttributeDefAssn(true);
3228           ruleAttrType.store();
3229         }
3230         
3231         //the attributes can only be assigned to the type def
3232         // try an attribute def dependent on an attribute def name
3233         ruleAttrType.getAttributeDefScopeDelegate().assignOwnerNameEquals(rule.getName());
3234 
3235         //add some names
3236         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_ACT_AS_SUBJECT_ID, 
3237             "subject id to act as, mutually exclusive with identifier", wasInCheckConfig);
3238         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_ACT_AS_SUBJECT_IDENTIFIER, 
3239             "subject identifier to act as, mutually exclusive with id", wasInCheckConfig);
3240         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_ACT_AS_SUBJECT_SOURCE_ID, 
3241             "subject source id to act as", wasInCheckConfig);
3242         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_CHECK_TYPE, 
3243             "when the check should be to see if rule should fire, enum: RuleCheckType", wasInCheckConfig);
3244         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_CHECK_OWNER_ID, 
3245             "when the check should be to see if rule should fire, this is owner of type, mutually exclusive with name", wasInCheckConfig);
3246         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_CHECK_OWNER_NAME, 
3247             "when the check should be to see if rule should fire, this is owner of type, mutually exclusice with id", wasInCheckConfig);
3248         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_CHECK_STEM_SCOPE, 
3249             "when the check is a stem type, this is Stem.Scope ALL or SUB", wasInCheckConfig);
3250         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_CHECK_ARG0, 
3251             "when the check needs an arg, this is the arg0", wasInCheckConfig);
3252         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_CHECK_ARG1, 
3253             "when the check needs an arg, this is the arg1", wasInCheckConfig);
3254         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_IF_OWNER_ID, 
3255             "when the if part has an arg, this is owner of if, mutually exclusive with name", wasInCheckConfig);
3256         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_IF_OWNER_NAME, 
3257             "when the if part has an arg, this is owner of if, mutually exclusive with id", wasInCheckConfig);
3258         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_IF_CONDITION_EL, 
3259             "expression language to run to see if the rule should run, or blank if should run always", wasInCheckConfig);
3260         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_IF_CONDITION_ENUM, 
3261             "RuleIfConditionEnum that sees if rule should fire, or exclude if should run always", wasInCheckConfig);
3262         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_IF_CONDITION_ENUM_ARG0, 
3263             "RuleIfConditionEnumArg0 if the if condition takes an argument, this is the first one", wasInCheckConfig);
3264         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_IF_CONDITION_ENUM_ARG1, 
3265             "RuleIfConditionEnumArg1 if the if condition takes an argument, this is the second param", wasInCheckConfig);
3266         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_IF_STEM_SCOPE, 
3267             "when the if part is a stem, this is the scope of SUB or ONE", wasInCheckConfig);
3268         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_THEN_EL, 
3269             "expression language to run when the rule fires", wasInCheckConfig);
3270         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_THEN_ENUM, 
3271             "RuleThenEnum to run when the rule fires", wasInCheckConfig);
3272         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_THEN_ENUM_ARG0, 
3273             "RuleThenEnum argument 0 to run when the rule fires (enum might need args)", wasInCheckConfig);
3274         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_THEN_ENUM_ARG1, 
3275             "RuleThenEnum argument 1 to run when the rule fires (enum might need args)", wasInCheckConfig);
3276         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_THEN_ENUM_ARG2, 
3277             "RuleThenEnum argument 2 to run when the rule fires (enum might need args)", wasInCheckConfig);
3278         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_VALID, 
3279             "T|F for if this rule is valid, or the reason, managed by hook automatically", wasInCheckConfig);
3280         checkAttribute(rulesStem, ruleAttrType, RuleUtils.RULE_RUN_DAEMON, 
3281             "T|F for if this rule daemon should run.  Default to true if blank and check and if are enums, false if not", wasInCheckConfig);
3282         
3283       }      
3284 
3285       boolean permissionsLimitsPublic = GrouperConfig.retrieveConfig().propertyValueBoolean("grouper.permissions.limits.builtin.createAs.public", true);
3286       
3287       {
3288         String limitsRootStemName = PermissionLimitUtils.attributeLimitStemName();
3289         
3290         Stem limitsStem = StemFinder.findByName(grouperSession, limitsRootStemName, false, new QueryOptions().secondLevelCache(false));
3291         if (limitsStem == null) {
3292           limitsStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
3293             .assignDescription("folder for built in Grouper permission limits").assignName(limitsRootStemName)
3294             .save();
3295         }
3296 
3297         //see if attributeDef is there
3298         String limitDefName = limitsRootStemName + ":" + PermissionLimitUtils.LIMIT_DEF;
3299         AttributeDef limitDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3300             limitDefName, false, new QueryOptions().secondLevelCache(false));
3301         if (limitDef == null) {
3302           limitDef = limitsStem.addChildAttributeDef(PermissionLimitUtils.LIMIT_DEF, AttributeDefType.limit);
3303           limitDef.setAssignToGroup(true);
3304           limitDef.setAssignToAttributeDef(true);
3305           limitDef.setAssignToGroupAssn(true);
3306           limitDef.setAssignToEffMembership(true);
3307           limitDef.setAssignToEffMembershipAssn(true);
3308           limitDef.setValueType(AttributeDefValueType.string);
3309           limitDef.setMultiAssignable(true);
3310           limitDef.store();
3311           
3312           if (permissionsLimitsPublic) {
3313             limitDef.getPrivilegeDelegate().grantPriv(SubjectFinder.findAllSubject(), AttributeDefPrivilege.ATTR_READ, false);
3314             limitDef.getPrivilegeDelegate().grantPriv(SubjectFinder.findAllSubject(), AttributeDefPrivilege.ATTR_UPDATE, false);
3315           }
3316           
3317         }
3318         
3319         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(limitDef);
3320 
3321         //add an el
3322         {
3323           String elDisplayExtension = StringUtils.defaultIfEmpty(GrouperConfig.retrieveConfig().propertyValueString("grouper.permissions.limits.builtin.displayExtension.limitExpression"), "Expression");
3324           checkAttribute(limitsStem, limitDef, PermissionLimitUtils.LIMIT_EL, elDisplayExtension, 
3325               "An expression language limit has a value of an EL which evaluates to true or false", wasInCheckConfig);
3326         }
3327         {
3328           String ipOnNetworksDisplayExtension = StringUtils.defaultIfEmpty(GrouperConfig.retrieveConfig().propertyValueString("grouper.permissions.limits.builtin.displayExtension.limitIpOnNetworks"), "ipAddress on networks");
3329           checkAttribute(limitsStem, limitDef, PermissionLimitUtils.LIMIT_IP_ON_NETWORKS, ipOnNetworksDisplayExtension,
3330               "If the user is on an IP address on the following networks", wasInCheckConfig);
3331         }
3332         {
3333           String ipOnNetworkRealmDisplayEntension = StringUtils.defaultIfEmpty(GrouperConfig.retrieveConfig().propertyValueString("grouper.permissions.limits.builtin.displayExtension.limitIpOnNetworkRealm"), "ipAddress on network realm");
3334           checkAttribute(limitsStem, limitDef, PermissionLimitUtils.LIMIT_IP_ON_NETWORK_REALM, ipOnNetworkRealmDisplayEntension,
3335               "If the user is on an IP address on a centrally configured list of addresses", wasInCheckConfig);
3336         }
3337         {
3338           String labelsContainDisplayExtension = StringUtils.defaultIfEmpty(GrouperConfig.retrieveConfig().propertyValueString("grouper.permissions.limits.builtin.displayExtension.limitLabelsContain"), "labels contains");
3339           checkAttribute(limitsStem, limitDef, PermissionLimitUtils.LIMIT_LABELS_CONTAIN, labelsContainDisplayExtension,
3340               "Configure a set of comma separated labels.  The env variable 'labels' should be passed with comma separated " +
3341               "labels.  If one is there, its ok, if not, then disallowed", wasInCheckConfig);
3342         }
3343       }
3344       
3345       {
3346         String limitsRootStemName = PermissionLimitUtils.attributeLimitStemName();
3347         Stem limitsStem = StemFinder.findByName(grouperSession, limitsRootStemName, true, new QueryOptions().secondLevelCache(false));
3348 
3349         //see if attributeDef is there
3350         String limitDefIntName = limitsRootStemName + ":" + PermissionLimitUtils.LIMIT_DEF_INT;
3351         AttributeDef limitDefInt = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3352             limitDefIntName, false, new QueryOptions().secondLevelCache(false));
3353         if (limitDefInt == null) {
3354           limitDefInt = limitsStem.addChildAttributeDef(PermissionLimitUtils.LIMIT_DEF_INT, AttributeDefType.limit);
3355           limitDefInt.setAssignToGroup(true);
3356           limitDefInt.setAssignToAttributeDef(true);
3357           limitDefInt.setAssignToGroupAssn(true);
3358           limitDefInt.setAssignToEffMembership(true);
3359           limitDefInt.setAssignToEffMembershipAssn(true);
3360           limitDefInt.setMultiAssignable(true);
3361           limitDefInt.setValueType(AttributeDefValueType.integer);
3362           limitDefInt.store();
3363 
3364           if (permissionsLimitsPublic) {
3365             limitDefInt.getPrivilegeDelegate().grantPriv(SubjectFinder.findAllSubject(), AttributeDefPrivilege.ATTR_READ, false);
3366             limitDefInt.getPrivilegeDelegate().grantPriv(SubjectFinder.findAllSubject(), AttributeDefPrivilege.ATTR_UPDATE, false);
3367           }
3368         }
3369         
3370         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(limitDefInt);
3371 
3372         {
3373           String limitAmountLessThanDisplayExtension = StringUtils.defaultIfEmpty(GrouperConfig.retrieveConfig().propertyValueString("grouper.permissions.limits.builtin.displayExtension.limitAmountLessThan"), "amount less than");
3374           checkAttribute(limitsStem, limitDefInt, PermissionLimitUtils.LIMIT_AMOUNT_LESS_THAN, limitAmountLessThanDisplayExtension, 
3375               "Make sure the amount is less than the configured value", wasInCheckConfig);
3376         }
3377         {
3378           String limitAmountLessThanOrEqualToDisplayExtension = StringUtils.defaultIfEmpty(GrouperConfig.retrieveConfig().propertyValueString("grouper.permissions.limits.builtin.displayExtension.limitAmountLessThanOrEqual"), "amount less than or equal to");
3379           checkAttribute(limitsStem, limitDefInt, PermissionLimitUtils.LIMIT_AMOUNT_LESS_THAN_OR_EQUAL, limitAmountLessThanOrEqualToDisplayExtension,
3380               "Make sure the amount is less or equal to the configured value", wasInCheckConfig);
3381         }
3382         
3383       }
3384 
3385       {
3386         String limitsRootStemName = PermissionLimitUtils.attributeLimitStemName();
3387         Stem limitsStem = StemFinder.findByName(grouperSession, limitsRootStemName, true, new QueryOptions().secondLevelCache(false));
3388 
3389         //see if attributeDef is there
3390         String limitDefMarkerName = limitsRootStemName + ":" + PermissionLimitUtils.LIMIT_DEF_MARKER;
3391         AttributeDef limitDefMarker = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3392             limitDefMarkerName, false, new QueryOptions().secondLevelCache(false));
3393         if (limitDefMarker == null) {
3394           limitDefMarker = limitsStem.addChildAttributeDef(PermissionLimitUtils.LIMIT_DEF_MARKER, AttributeDefType.limit);
3395           limitDefMarker.setAssignToGroup(true);
3396           limitDefMarker.setAssignToAttributeDef(true);
3397           limitDefMarker.setAssignToGroupAssn(true);
3398           limitDefMarker.setAssignToEffMembershipAssn(true);
3399           limitDefMarker.setAssignToEffMembership(true);
3400           limitDefMarker.setMultiAssignable(true);
3401           limitDefMarker.setValueType(AttributeDefValueType.marker);
3402           limitDefMarker.store();
3403 
3404           if (permissionsLimitsPublic) {
3405             limitDefMarker.getPrivilegeDelegate().grantPriv(SubjectFinder.findAllSubject(), AttributeDefPrivilege.ATTR_READ, false);
3406             limitDefMarker.getPrivilegeDelegate().grantPriv(SubjectFinder.findAllSubject(), AttributeDefPrivilege.ATTR_UPDATE, false);
3407           }
3408         }
3409 
3410         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(limitDefMarker);
3411         
3412         {
3413           String limitAmountLessThanDisplayExtension = StringUtils.defaultIfEmpty(GrouperConfig.retrieveConfig().propertyValueString("grouper.permissions.limits.builtin.displayExtension.limitWeekday9to5"), "Weekday 9 to 5");
3414           //add an weekday 9 to 5
3415           checkAttribute(limitsStem, limitDefMarker, PermissionLimitUtils.LIMIT_WEEKDAY_9_TO_5, limitAmountLessThanDisplayExtension,
3416               "Make sure the check for the permission happens between 9am to 5pm on Monday through Friday", wasInCheckConfig);
3417         }
3418       }
3419 
3420 
3421       AttributeDefName attributeLoaderTypeName = null;
3422       
3423       {
3424         String loaderRootStemName = attributeLoaderStemName();
3425         
3426         Stem loaderStem = StemFinder.findByName(grouperSession, loaderRootStemName, false, new QueryOptions().secondLevelCache(false));
3427         if (loaderStem == null) {
3428           loaderStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
3429             .assignDescription("folder for built in Grouper loader attributes").assignName(loaderRootStemName)
3430             .save();
3431         }
3432 
3433         //see if attributeDef is there
3434         String attributeDefLoaderTypeDefName = loaderRootStemName + ":attributeDefLoaderTypeDef";
3435         AttributeDef attributeDefType = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3436             attributeDefLoaderTypeDefName, false, new QueryOptions().secondLevelCache(false));
3437         if (attributeDefType == null) {
3438           attributeDefType = loaderStem.addChildAttributeDef("attributeDefLoaderTypeDef", AttributeDefType.type);
3439           attributeDefType.setAssignToAttributeDef(true);
3440           attributeDefType.store();
3441         }
3442         
3443         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(attributeDefType);
3444         
3445         //add a name
3446         attributeLoaderTypeName = checkAttribute(loaderStem, attributeDefType, "attributeLoader", 
3447             "is a loader based attribute def, the loader attributes will be available to be assigned", wasInCheckConfig);
3448         
3449         //see if attributeDef is there
3450         String attributeDefLoaderDefName = loaderRootStemName + ":attributeDefLoaderDef";
3451         AttributeDef attributeDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3452           attributeDefLoaderDefName, false, new QueryOptions().secondLevelCache(false));
3453         if (attributeDef == null) {
3454           attributeDef = loaderStem.addChildAttributeDef("attributeDefLoaderDef", AttributeDefType.attr);
3455           attributeDef.setAssignToAttributeDef(true);
3456           attributeDef.setValueType(AttributeDefValueType.string);
3457           attributeDef.store();
3458         }
3459         
3460         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(attributeDef);
3461         
3462         //make sure the other def means this one is allowed
3463         attributeDef.getAttributeDefScopeDelegate().assignTypeDependence(attributeLoaderTypeName);
3464         
3465         //add some names
3466         checkAttribute(loaderStem, attributeDef, "attributeLoaderType", "Type of loader, e.g. ATTR_SQL_SIMPLE", wasInCheckConfig);
3467         checkAttribute(loaderStem, attributeDef, "attributeLoaderDbName", 
3468           "DB name in grouper-loader.properties or default grouper db if blank", wasInCheckConfig);
3469         checkAttribute(loaderStem, attributeDef, "attributeLoaderScheduleType", 
3470           "Type of schedule.  Defaults to CRON if a cron schedule is entered, or START_TO_START_INTERVAL if an interval is entered", wasInCheckConfig);
3471         checkAttribute(loaderStem, attributeDef, "attributeLoaderQuartzCron", 
3472           "If a CRON schedule type, this is the cron setting string from the quartz product to run a job daily, hourly, weekly, etc.  e.g. daily at 7am: 0 0 7 * * ?", wasInCheckConfig);
3473         checkAttribute(loaderStem, attributeDef, "attributeLoaderIntervalSeconds", 
3474           "If a START_TO_START_INTERVAL schedule type, this is the number of seconds between runs", wasInCheckConfig);
3475         checkAttribute(loaderStem, attributeDef, "attributeLoaderPriority", 
3476           "Quartz has a fixed threadpool (max configured in the grouper-loader.properties), and when the max is reached, then jobs are prioritized by this integer.  The higher the better, and the default if not set is 5.", wasInCheckConfig);
3477         checkAttribute(loaderStem, attributeDef, "attributeLoaderAttrsLike", 
3478           "If empty, then orphans will be left alone (for attributeDefName and attributeDefNameSets).  If %, then all orphans deleted.  If a SQL like string, then only ones in that like string not in loader will be deleted", wasInCheckConfig);
3479         checkAttribute(loaderStem, attributeDef, "attributeLoaderAttrQuery", 
3480           "SQL query with at least some of the following columns: attr_name, attr_display_name, attr_description", wasInCheckConfig);
3481         checkAttribute(loaderStem, attributeDef, "attributeLoaderAttrSetQuery", 
3482           "SQL query with at least the following columns: if_has_attr_name, then_has_attr_name", wasInCheckConfig);
3483         checkAttribute(loaderStem, attributeDef, "attributeLoaderActionQuery", 
3484             "SQL query with at least the following column: action_name", wasInCheckConfig);
3485         checkAttribute(loaderStem, attributeDef, "attributeLoaderActionSetQuery", 
3486             "SQL query with at least the following columns: if_has_action_name, then_has_action_name", wasInCheckConfig);
3487                 
3488       }
3489 
3490       {
3491         String loaderLdapRootStemName = LoaderLdapUtils.attributeLoaderLdapStemName();
3492         
3493         Stem loaderLdapStem = StemFinder.findByName(grouperSession, loaderLdapRootStemName, false, new QueryOptions().secondLevelCache(false));
3494         if (loaderLdapStem == null) {
3495           loaderLdapStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
3496             .assignDescription("folder for built in Grouper loader ldap attributes").assignName(loaderLdapRootStemName)
3497             .save();
3498         }
3499 
3500         {
3501           //see if attributeDef is there
3502           String loaderLdapDefName = loaderLdapRootStemName + ":" + LoaderLdapUtils.LOADER_LDAP_DEF;
3503           AttributeDef loaderLdapDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3504               loaderLdapDefName, false, new QueryOptions().secondLevelCache(false));
3505           if (loaderLdapDef == null) {
3506             loaderLdapDef = loaderLdapStem.addChildAttributeDef(LoaderLdapUtils.LOADER_LDAP_DEF, AttributeDefType.attr);
3507             loaderLdapDef.setAssignToGroup(true);
3508             loaderLdapDef.setValueType(AttributeDefValueType.marker);
3509             loaderLdapDef.store();
3510           }
3511           
3512           Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(loaderLdapDef);
3513           
3514           //add an attribute for the loader ldap marker
3515           {
3516             checkAttribute(loaderLdapStem, loaderLdapDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_MARKER, "Grouper loader LDAP", 
3517                 "Marks a group to be processed by the Grouper loader as an LDAP synced job", wasInCheckConfig);
3518           }
3519         }
3520         {
3521           //see if attributeDef is there
3522           String loaderLdapValueDefName = loaderLdapRootStemName + ":" + LoaderLdapUtils.LOADER_LDAP_VALUE_DEF;
3523           AttributeDef loaderLdapValueDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3524               loaderLdapValueDefName, false, new QueryOptions().secondLevelCache(false));
3525           if (loaderLdapValueDef == null) {
3526             loaderLdapValueDef = loaderLdapStem.addChildAttributeDef(LoaderLdapUtils.LOADER_LDAP_VALUE_DEF, AttributeDefType.attr);
3527             loaderLdapValueDef.setAssignToGroupAssn(true);
3528             loaderLdapValueDef.setValueType(AttributeDefValueType.string);
3529             loaderLdapValueDef.store();
3530           }
3531           
3532           Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(loaderLdapValueDef);
3533           
3534           //add an attribute for the loader ldap marker
3535           {
3536             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_TYPE, "Grouper loader LDAP type", 
3537                 "This holds the type of job from the GrouperLoaderType enum, currently the only valid values are " +
3538                 "LDAP_SIMPLE, LDAP_GROUP_LIST, LDAP_GROUPS_FROM_ATTRIBUTES. Simple is a group loaded from LDAP " +
3539                 "filter which returns subject ids or identifiers.  Group list is an LDAP filter which returns " +
3540                 "group objects, and the group objects have a list of subjects.  Groups from attributes is an LDAP " +
3541                 "filter that returns subjects which have a multi-valued attribute e.g. affiliations where groups " +
3542                 "will be created based on subject who have each attribute value  ", wasInCheckConfig);
3543             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_SERVER_ID, "Grouper loader LDAP server ID", 
3544                 "Server ID that is configured in the grouper-loader.properties that identifies the connection information to the LDAP server", wasInCheckConfig);
3545             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_FILTER, "Grouper loader LDAP filter", 
3546                 "LDAP filter returns objects that have subjectIds or subjectIdentifiers and group name (if LDAP_GROUP_LIST)", wasInCheckConfig);
3547             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_QUARTZ_CRON, 
3548                 "Grouper loader LDAP quartz cron", 
3549                 "Quartz cron config string, e.g. every day at 8am is: 0 0 8 * * ?", wasInCheckConfig);
3550             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_SEARCH_DN, "Grouper loader LDAP search base DN", 
3551                 "Location that constrains the subtree where the filter is applicable", wasInCheckConfig);
3552             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_SUBJECT_ATTRIBUTE, 
3553                 "Grouper loader LDAP subject attribute name", 
3554                 "Attribute name of the filter object result that holds the subject id.  Note, if you use 'dn', and " +
3555                 "dn is not an attribute of the object, then the fully qualified object name will be used", wasInCheckConfig);
3556             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_SOURCE_ID, 
3557                 "Grouper loader LDAP source ID", 
3558                 "Source ID from the subject.properties that narrows the search for subjects.  This is optional though makes the loader job more efficient", wasInCheckConfig);
3559             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_SUBJECT_ID_TYPE, 
3560                 "Grouper loader LDAP subject ID type", 
3561                 "The type of subject ID.  This can be either: subjectId (most efficient), subjectIdentifier (2nd most efficient), or subjectIdOrIdentifier", wasInCheckConfig);
3562             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_AND_GROUPS, 
3563                 "Grouper loader LDAP require in groups", 
3564                 "If you want to restrict membership in the dynamic group based on other group(s), put the list of group names " +
3565                 "here comma-separated.  The require groups means if you put a group names in there (e.g. school:community:employee) " +
3566                 "then it will 'and' that group with the member list from the loader.  So only members of the group from the loader " +
3567                 "query who are also employees will be in the resulting group", wasInCheckConfig);
3568             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_SEARCH_SCOPE, 
3569                 "Grouper loader LDAP search scope", 
3570                 "How the deep in the subtree the search will take place.  Can be OBJECT_SCOPE, ONELEVEL_SCOPE, or SUBTREE_SCOPE (default)", wasInCheckConfig);
3571             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_PRIORITY, 
3572                 "Grouper loader LDAP scheduling priority", 
3573                 "Quartz has a fixed threadpool (max configured in the grouper-loader.properties), and when the max is reached, " +
3574                 "then jobs are prioritized by this integer.  The higher the better, and the default if not set is 5.", wasInCheckConfig);
3575             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_GROUPS_LIKE, 
3576                 "Grouper loader LDAP groups like", 
3577                 "This should be a sql like string (e.g. school:orgs:%org%_systemOfRecord), and the loader should be able to query group names to " +
3578                 "see which names are managed by this loader job.  So if a group falls off the loader resultset (or is moved), this will help the " +
3579                 "loader remove the members from this group.  Note, if the group is used anywhere as a member or composite member, it wont be removed.  " +
3580                 "All include/exclude/requireGroups will be removed.  Though the two groups, include and exclude, will not be removed if they have members.  " +
3581                 "There is a grouper-loader.properties setting to remove loader groups if empty and not used: " +
3582                 "#if using a sql table, and specifying the name like string, then shoudl the group (in addition to memberships)" +
3583                 "# be removed if not used anywhere else?" +
3584                 "loader.sqlTable.likeString.removeGroupIfNotUsed = true", wasInCheckConfig);
3585             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_RESULTS_TRANSFORMATION_CLASS, 
3586                 "Grouper loader LDAP results transformation class (optional for loader ldap type: LDAP_GROUPS_FROM_ATTRIBUTE)", wasInCheckConfig);
3587             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_GROUP_ATTRIBUTE, 
3588                 "Grouper loader LDAP group attribute name", 
3589                 "Attribute name of the filter object result that holds the group name (required for " +
3590                 "loader ldap type: LDAP_GROUPS_FROM_ATTRIBUTE)", wasInCheckConfig);
3591             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_ATTRIBUTE_FILTER_EXPRESSION, 
3592                 "Grouper loader LDAP attribute filter expression", 
3593                 "JEXL expression that returns true or false to signify if an attribute (in GROUPS_FROM_ATTRIBUTES) is ok to use for a group.  " +
3594                 "attributeValue is the variable that is the value of the attribute.", wasInCheckConfig);
3595             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_EXTRA_ATTRIBUTES, 
3596                 "Grouper loader LDAP extra attributes", 
3597                 "Attribute names (comma separated) to get LDAP data for expressions in group name, displayExtension, description, " +
3598                 "optional, for LDAP_GROUP_LIST", wasInCheckConfig);
3599             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_GROUP_NAME_EXPRESSION, 
3600                 "Grouper loader LDAP group name expression", 
3601                 "JEXL expression language fragment that evaluates to the group name (relative in the stem as the " +
3602                 "group which has the loader definition), optional, for LDAP_GROUP_LIST, or LDAP_GROUPS_FROM_ATTRIBUTES", 
3603                 wasInCheckConfig);
3604             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_GROUP_DISPLAY_NAME_EXPRESSION, 
3605                 "Grouper loader LDAP group display name expression", 
3606                 "JEXL expression language fragment that evaluates to the group display name, optional for " +
3607                 "LDAP_GROUP_LIST or LDAP_GROUPS_FROM_ATTRIBUTES", 
3608                 wasInCheckConfig);
3609             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_GROUP_DESCRIPTION_EXPRESSION, 
3610                 "Grouper loader LDAP group description expression", 
3611                 "JEXL expression language fragment that evaluates to the group description, " +
3612                 "optional for LDAP_GROUP_LIST or LDAP_GROUPS_FROM_ATTRIBUTES", 
3613                 wasInCheckConfig);
3614             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_SUBJECT_EXPRESSION, 
3615                 "Grouper loader LDAP subject expression", 
3616                 "JEXL expression language fragment that processes the subject string before passing it to the subject API (optional)", 
3617                 wasInCheckConfig);
3618             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_GROUP_TYPES, 
3619                 "Grouper loader LDAP group types", 
3620                 "Comma separated GroupTypes which will be applied to the loaded groups.  The reason this enhancement " +
3621                 "exists is so we can do a group list filter and attach addIncludeExclude to the groups.  Note, if you " +
3622                 "do this (or use some requireGroups), the group name in the loader query should end in the system of " +
3623                 "record suffix, which by default is _systemOfRecord. optional for LDAP_GROUP_LIST or LDAP_GROUPS_FROM_ATTRIBUTES", 
3624                 wasInCheckConfig);
3625 
3626             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_READERS, 
3627                 "Grouper loader LDAP group readers", 
3628                 "Comma separated subjectIds or subjectIdentifiers who will be allowed to READ the group membership.  " +
3629                 "optional for LDAP_GROUP_LIST or LDAP_GROUPS_FROM_ATTRIBUTES", 
3630                 wasInCheckConfig);
3631             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_VIEWERS, 
3632                 "Grouper loader LDAP group viewers", 
3633                 "Comma separated subjectIds or subjectIdentifiers who will be allowed to VIEW the group.  " +
3634                 "optional for LDAP_GROUP_LIST or LDAP_GROUPS_FROM_ATTRIBUTES", 
3635                 wasInCheckConfig);
3636             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_ADMINS, 
3637                 "Grouper loader LDAP group admins", 
3638                 "Comma separated subjectIds or subjectIdentifiers who will be allowed to ADMIN the group.  " +
3639                 "optional for LDAP_GROUP_LIST or LDAP_GROUPS_FROM_ATTRIBUTES", 
3640                 wasInCheckConfig);
3641             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_UPDATERS, 
3642                 "Grouper loader LDAP group updaters", 
3643                 "Comma separated subjectIds or subjectIdentifiers who will be allowed to UPDATE the group memberships.  " +
3644                 "optional for LDAP_GROUP_LIST or LDAP_GROUPS_FROM_ATTRIBUTES", 
3645                 wasInCheckConfig);
3646             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_OPTINS, 
3647                 "Grouper loader LDAP group optins", 
3648                 "Comma separated subjectIds or subjectIdentifiers who will be allowed to OPT IN to the group membership list.  " +
3649                 "optional for LDAP_GROUP_LIST or LDAP_GROUPS_FROM_ATTRIBUTES", 
3650                 wasInCheckConfig);
3651             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_OPTOUTS, 
3652                 "Grouper loader LDAP group optouts", 
3653                 "Comma separated subjectIds or subjectIdentifiers who will be allowed to OPT OUT of the group membership list.  " +
3654                 "optional for LDAP_GROUP_LIST or LDAP_GROUPS_FROM_ATTRIBUTES", 
3655                 wasInCheckConfig);
3656             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_GROUP_ATTR_READERS, 
3657                 "Grouper loader LDAP group attribute readers", 
3658                 "Comma separated subjectIds or subjectIdentifiers who will be allowed to GROUP_ATTR_READ on the group.  " +
3659                 "optional for LDAP_GROUP_LIST or LDAP_GROUPS_FROM_ATTRIBUTES", 
3660                 wasInCheckConfig);
3661             checkAttribute(loaderLdapStem, loaderLdapValueDef, LoaderLdapUtils.ATTR_DEF_EXTENSION_LDAP_GROUP_ATTR_UPDATERS, 
3662                 "Grouper loader LDAP group attribute updaters", 
3663                 "Comma separated subjectIds or subjectIdentifiers who will be allowed to GROUP_ATTR_UPDATE on the group.  " +
3664                 "optional for LDAP_GROUP_LIST or LDAP_GROUPS_FROM_ATTRIBUTES", 
3665                 wasInCheckConfig);
3666           }
3667         }
3668       }
3669       
3670       {
3671         String upgradeTasksRootStemName = UpgradeTasksJob.grouperUpgradeTasksStemName();
3672         
3673         Stem upgradeTasksRootStem = StemFinder.findByName(grouperSession, upgradeTasksRootStemName, false, new QueryOptions().secondLevelCache(false));
3674         if (upgradeTasksRootStem == null) {
3675           upgradeTasksRootStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
3676             .assignDescription("folder for upgrade tasks objects").assignName(upgradeTasksRootStemName)
3677             .save();
3678         }
3679 
3680         // check attribute def
3681         String upgradeTasksDefName = upgradeTasksRootStemName + ":" + UpgradeTasksJob.UPGRADE_TASKS_DEF;
3682         AttributeDef upgradeTasksDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3683             upgradeTasksDefName, false, new QueryOptions().secondLevelCache(false));
3684         if (upgradeTasksDef == null) {
3685           upgradeTasksDef = upgradeTasksRootStem.addChildAttributeDef(UpgradeTasksJob.UPGRADE_TASKS_DEF, AttributeDefType.attr);
3686           upgradeTasksDef.setAssignToGroup(true);
3687           upgradeTasksDef.setValueType(AttributeDefValueType.string);
3688           upgradeTasksDef.store();
3689         }
3690         
3691         String upgradeTasksVersionName = upgradeTasksRootStemName + ":" + UpgradeTasksJob.UPGRADE_TASKS_VERSION_ATTR;
3692         
3693         AttributeDefName upgradeTasksVersion = GrouperDAOFactory.getFactory().getAttributeDefName().findByNameSecure(
3694             upgradeTasksVersionName, false, new QueryOptions().secondLevelCache(false));
3695         
3696         if (upgradeTasksVersion == null) {
3697           upgradeTasksVersion = upgradeTasksRootStem.addChildAttributeDefName(upgradeTasksDef, UpgradeTasksJob.UPGRADE_TASKS_VERSION_ATTR, UpgradeTasksJob.UPGRADE_TASKS_VERSION_ATTR);
3698         }
3699         
3700         String groupName = upgradeTasksRootStemName + ":" + UpgradeTasksJob.UPGRADE_TASKS_METADATA_GROUP;
3701         Group group = GrouperDAOFactory.getFactory().getGroup().findByNameSecure(
3702             groupName, false, new QueryOptions().secondLevelCache(false), GrouperUtil.toSet(TypeOfGroup.group));
3703         if (group == null) {
3704           group = upgradeTasksRootStem.addChildGroup(UpgradeTasksJob.UPGRADE_TASKS_METADATA_GROUP, UpgradeTasksJob.UPGRADE_TASKS_METADATA_GROUP);
3705         }
3706         
3707         if (group.getAttributeValueDelegate().retrieveValueString(upgradeTasksVersionName) == null) {
3708           group.getAttributeValueDelegate().assignValue(upgradeTasksVersionName, "0");
3709         }
3710       }
3711             
3712       {
3713         String instrumentationDataRootStemName = InstrumentationDataUtils.grouperInstrumentationDataStemName();
3714         
3715         Stem instrumentationDataRootStem = StemFinder.findByName(grouperSession, instrumentationDataRootStemName, false, new QueryOptions().secondLevelCache(false));
3716         if (instrumentationDataRootStem == null) {
3717           instrumentationDataRootStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
3718             .assignDescription("folder for built in Grouper instrumentation data attributes").assignName(instrumentationDataRootStemName)
3719             .save();
3720         }
3721         
3722         {
3723           // check instances folder
3724                     
3725           String instancesStemName = instrumentationDataRootStemName + ":" + InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCES_FOLDER;
3726           Stem instancesStem = StemFinder.findByName(grouperSession, instancesStemName, false, new QueryOptions().secondLevelCache(false));
3727           if (instancesStem == null) {
3728             new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
3729               .assignDescription("folder for Grouper instances").assignName(instancesStemName)
3730               .save();
3731           }
3732         }
3733         
3734         {
3735           // check collectors folder
3736                     
3737           String collectorsStemName = instrumentationDataRootStemName + ":" + InstrumentationDataUtils.INSTRUMENTATION_DATA_COLLECTORS_FOLDER;
3738           Stem collectorsStem = StemFinder.findByName(grouperSession, collectorsStemName, false, new QueryOptions().secondLevelCache(false));
3739           if (collectorsStem == null) {
3740             new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
3741               .assignDescription("folder for Grouper collectors").assignName(collectorsStemName)
3742               .save();
3743           }
3744         }
3745 
3746         {
3747           // check instances def
3748           String instancesDefName = instrumentationDataRootStemName + ":" + InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCES_DEF;
3749           AttributeDef instancesDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3750               instancesDefName, false, new QueryOptions().secondLevelCache(false));
3751           if (instancesDef == null) {
3752             instancesDef = instrumentationDataRootStem.addChildAttributeDef(InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCES_DEF, AttributeDefType.attr);
3753             instancesDef.setAssignToGroup(true);
3754             instancesDef.setValueType(AttributeDefValueType.marker);
3755             instancesDef.store();
3756           }
3757           
3758           Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(instancesDef);
3759           
3760         }
3761         
3762         {
3763           // check collectors def
3764           String collectorsDefName = instrumentationDataRootStemName + ":" + InstrumentationDataUtils.INSTRUMENTATION_DATA_COLLECTORS_DEF;
3765           AttributeDef collectorsDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3766               collectorsDefName, false, new QueryOptions().secondLevelCache(false));
3767           if (collectorsDef == null) {
3768             collectorsDef = instrumentationDataRootStem.addChildAttributeDef(InstrumentationDataUtils.INSTRUMENTATION_DATA_COLLECTORS_DEF, AttributeDefType.attr);
3769             collectorsDef.setAssignToGroup(true);
3770             collectorsDef.setValueType(AttributeDefValueType.marker);
3771             collectorsDef.store();
3772           }
3773 
3774           Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(collectorsDef);
3775           
3776         }
3777         
3778         {
3779           // check counts def and attr
3780           String countsDefName = instrumentationDataRootStemName + ":" + InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCE_COUNTS_DEF;
3781           AttributeDef countsDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3782               countsDefName, false, new QueryOptions().secondLevelCache(false));
3783           if (countsDef == null) {
3784             countsDef = instrumentationDataRootStem.addChildAttributeDef(InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCE_COUNTS_DEF, AttributeDefType.attr);
3785             countsDef.setAssignToGroupAssn(true);
3786             countsDef.setValueType(AttributeDefValueType.string);
3787             countsDef.setMultiValued(true);
3788             countsDef.store();
3789           }
3790           
3791           Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(countsDef);
3792           
3793           String countsDefNameName = instrumentationDataRootStemName + ":" + InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCE_COUNTS_ATTR;
3794           
3795           AttributeDefName countsAttrDefName = GrouperDAOFactory.getFactory().getAttributeDefName().findByNameSecure(
3796               countsDefNameName, false, new QueryOptions().secondLevelCache(false));
3797           
3798           if (countsAttrDefName == null) {
3799             countsAttrDefName = instrumentationDataRootStem.addChildAttributeDefName(countsDef, InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCE_COUNTS_ATTR, InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCE_COUNTS_ATTR);
3800           }
3801         }
3802         
3803         {
3804           // check instance details def and attrs
3805           String detailsDefName = instrumentationDataRootStemName + ":" + InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCE_DETAILS_DEF;
3806           AttributeDef detailsDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3807               detailsDefName, false, new QueryOptions().secondLevelCache(false));
3808           if (detailsDef == null) {
3809             detailsDef = instrumentationDataRootStem.addChildAttributeDef(InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCE_DETAILS_DEF, AttributeDefType.attr);
3810             detailsDef.setAssignToGroupAssn(true);
3811             detailsDef.setValueType(AttributeDefValueType.string);
3812             detailsDef.store();
3813           }
3814           
3815           Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(detailsDef);
3816           
3817           {
3818             String lastUpdateName = instrumentationDataRootStemName + ":" + InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCE_LAST_UPDATE_ATTR;
3819             
3820             AttributeDefName lastUpdate = GrouperDAOFactory.getFactory().getAttributeDefName().findByNameSecure(
3821                 lastUpdateName, false, new QueryOptions().secondLevelCache(false));
3822             
3823             if (lastUpdate == null) {
3824               lastUpdate = instrumentationDataRootStem.addChildAttributeDefName(detailsDef, InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCE_LAST_UPDATE_ATTR, InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCE_LAST_UPDATE_ATTR);
3825             }
3826           }
3827           
3828           {
3829             String engineNameName = instrumentationDataRootStemName + ":" + InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCE_ENGINE_NAME_ATTR;
3830             
3831             AttributeDefName engineName = GrouperDAOFactory.getFactory().getAttributeDefName().findByNameSecure(
3832                 engineNameName, false, new QueryOptions().secondLevelCache(false));
3833             
3834             if (engineName == null) {
3835               engineName = instrumentationDataRootStem.addChildAttributeDefName(detailsDef, InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCE_ENGINE_NAME_ATTR, InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCE_ENGINE_NAME_ATTR);
3836             }
3837           }
3838           
3839           {
3840             String serverLabelName = instrumentationDataRootStemName + ":" + InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCE_SERVER_LABEL_ATTR;
3841             
3842             AttributeDefName serverLabel = GrouperDAOFactory.getFactory().getAttributeDefName().findByNameSecure(
3843                 serverLabelName, false, new QueryOptions().secondLevelCache(false));
3844             
3845             if (serverLabel == null) {
3846               serverLabel = instrumentationDataRootStem.addChildAttributeDefName(detailsDef, InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCE_SERVER_LABEL_ATTR, InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCE_SERVER_LABEL_ATTR);
3847             }
3848           }
3849         }
3850         
3851         {
3852           // check collector details def and attrs
3853           String detailsDefName = instrumentationDataRootStemName + ":" + InstrumentationDataUtils.INSTRUMENTATION_DATA_COLLECTOR_DETAILS_DEF;
3854           AttributeDef detailsDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3855               detailsDefName, false, new QueryOptions().secondLevelCache(false));
3856           if (detailsDef == null) {
3857             detailsDef = instrumentationDataRootStem.addChildAttributeDef(InstrumentationDataUtils.INSTRUMENTATION_DATA_COLLECTOR_DETAILS_DEF, AttributeDefType.attr);
3858             detailsDef.setAssignToGroupAssn(true);
3859             detailsDef.setValueType(AttributeDefValueType.string);
3860             detailsDef.store();
3861           }
3862           
3863           Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(detailsDef);
3864           
3865           {
3866             String lastUpdateName = instrumentationDataRootStemName + ":" + InstrumentationDataUtils.INSTRUMENTATION_DATA_COLLECTOR_LAST_UPDATE_ATTR;
3867             
3868             AttributeDefName lastUpdate = GrouperDAOFactory.getFactory().getAttributeDefName().findByNameSecure(
3869                 lastUpdateName, false, new QueryOptions().secondLevelCache(false));
3870             
3871             if (lastUpdate == null) {
3872               lastUpdate = instrumentationDataRootStem.addChildAttributeDefName(detailsDef, InstrumentationDataUtils.INSTRUMENTATION_DATA_COLLECTOR_LAST_UPDATE_ATTR, InstrumentationDataUtils.INSTRUMENTATION_DATA_COLLECTOR_LAST_UPDATE_ATTR);
3873             }
3874           }
3875           
3876           {
3877             String uuidName = instrumentationDataRootStemName + ":" + InstrumentationDataUtils.INSTRUMENTATION_DATA_COLLECTOR_UUID_ATTR;
3878             
3879             AttributeDefName uuid = GrouperDAOFactory.getFactory().getAttributeDefName().findByNameSecure(
3880                 uuidName, false, new QueryOptions().secondLevelCache(false));
3881             
3882             if (uuid == null) {
3883               uuid = instrumentationDataRootStem.addChildAttributeDefName(detailsDef, InstrumentationDataUtils.INSTRUMENTATION_DATA_COLLECTOR_UUID_ATTR, InstrumentationDataUtils.INSTRUMENTATION_DATA_COLLECTOR_UUID_ATTR);
3884             }
3885           }
3886         }
3887         
3888         {
3889           // check instances group
3890           String groupName = instrumentationDataRootStemName + ":" + InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCES_GROUP;
3891           Group group = GrouperDAOFactory.getFactory().getGroup().findByNameSecure(
3892               groupName, false, new QueryOptions().secondLevelCache(false), GrouperUtil.toSet(TypeOfGroup.group));
3893           if (group == null) {
3894             group = instrumentationDataRootStem.addChildGroup(InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCES_GROUP, InstrumentationDataUtils.INSTRUMENTATION_DATA_INSTANCES_GROUP);
3895             GroupFinder.groupCacheAsRootAddSystemGroup(group);
3896           }
3897         }
3898         
3899         {
3900           // check collectors group
3901           String groupName = instrumentationDataRootStemName + ":" + InstrumentationDataUtils.INSTRUMENTATION_DATA_COLLECTORS_GROUP;
3902           Group group = GrouperDAOFactory.getFactory().getGroup().findByNameSecure(
3903               groupName, false, new QueryOptions().secondLevelCache(false), GrouperUtil.toSet(TypeOfGroup.group));
3904           if (group == null) {
3905             group = instrumentationDataRootStem.addChildGroup(InstrumentationDataUtils.INSTRUMENTATION_DATA_COLLECTORS_GROUP, InstrumentationDataUtils.INSTRUMENTATION_DATA_COLLECTORS_GROUP);
3906             GroupFinder.groupCacheAsRootAddSystemGroup(group);
3907           }
3908         }
3909       }
3910       
3911       {
3912         String userDataRootStemName = GrouperUserDataUtils.grouperUserDataStemName();
3913         
3914         Stem userDataStem = StemFinder.findByName(grouperSession, userDataRootStemName, false, new QueryOptions().secondLevelCache(false));
3915         if (userDataStem == null) {
3916           userDataStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
3917             .assignDescription("folder for built in Grouper user data attributes").assignName(userDataRootStemName)
3918             .save();
3919         }
3920 
3921         {
3922           //see if attributeDef is there
3923           String userDataDefName = userDataRootStemName + ":" + GrouperUserDataUtils.USER_DATA_DEF;
3924           AttributeDef userDataDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3925               userDataDefName, false, new QueryOptions().secondLevelCache(false));
3926           if (userDataDef == null) {
3927             userDataDef = userDataStem.addChildAttributeDef(GrouperUserDataUtils.USER_DATA_DEF, AttributeDefType.attr);
3928             userDataDef.setAssignToImmMembership(true);
3929             userDataDef.setValueType(AttributeDefValueType.marker);
3930             userDataDef.store();
3931           }
3932           
3933           Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(userDataDef);
3934           
3935           //add an attribute for the loader ldap marker
3936           {
3937             checkAttribute(userDataStem, userDataDef, GrouperUserDataUtils.ATTR_DEF_EXTENSION_MARKER, "Grouper user data", 
3938                 "Marks a group that has memberships which have attributes for user data", wasInCheckConfig);
3939           }
3940         }
3941         {
3942           //see if attributeDef is there
3943           String userDataValueDefName = userDataRootStemName + ":" + GrouperUserDataUtils.USER_DATA_VALUE_DEF;
3944           AttributeDef userDataValueDef = GrouperDAOFactory.getFactory().getAttributeDef().findByNameSecure(
3945               userDataValueDefName, false, new QueryOptions().secondLevelCache(false));
3946           if (userDataValueDef == null) {
3947             userDataValueDef = userDataStem.addChildAttributeDef(GrouperUserDataUtils.USER_DATA_VALUE_DEF, AttributeDefType.attr);
3948             userDataValueDef.setAssignToImmMembershipAssn(true);
3949             userDataValueDef.setValueType(AttributeDefValueType.string);
3950             userDataValueDef.store();
3951           }
3952           
3953           Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(userDataValueDef);
3954           
3955           //add an attribute for the loader ldap marker
3956           {
3957             checkAttribute(userDataStem, userDataValueDef, GrouperUserDataUtils.ATTR_DEF_EXTENSION_FAVORITE_GROUPS, 
3958                 "Grouper user data favorite groups", 
3959                 "A list of group ids and metadata in json format that are the favorites for a user", wasInCheckConfig);
3960             checkAttribute(userDataStem, userDataValueDef, GrouperUserDataUtils.ATTR_DEF_EXTENSION_FAVORITE_SUBJECTS, 
3961                 "Grouper user data favorite subjects", 
3962                 "A list of member ids and metadata in json format that are the favorites for a user", wasInCheckConfig);
3963             checkAttribute(userDataStem, userDataValueDef, GrouperUserDataUtils.ATTR_DEF_EXTENSION_RECENT_GROUPS, 
3964                 "Grouper user data recent groups", 
3965                 "A list of group ids and metadata in json format that are the recently used groups for a user", wasInCheckConfig);
3966             checkAttribute(userDataStem, userDataValueDef, GrouperUserDataUtils.ATTR_DEF_EXTENSION_FAVORITE_STEMS, 
3967                 "Grouper user data favorite folders", 
3968                 "A list of folder ids and metadata in json format that are the favorites for a user", wasInCheckConfig);
3969             checkAttribute(userDataStem, userDataValueDef, GrouperUserDataUtils.ATTR_DEF_EXTENSION_RECENT_STEMS, 
3970                 "Grouper user data recent folders", 
3971                 "A list of folder ids and metadata in json format that are the recently used folders for a user", wasInCheckConfig);
3972             checkAttribute(userDataStem, userDataValueDef, GrouperUserDataUtils.ATTR_DEF_EXTENSION_RECENT_ATTIRBUTE_DEFS, 
3973                 "Grouper user data recent attribute definitions", 
3974                 "A list of attribute definition ids and metadata in json format that are the recently used attribute definitions for a user", wasInCheckConfig);
3975             checkAttribute(userDataStem, userDataValueDef, GrouperUserDataUtils.ATTR_DEF_EXTENSION_RECENT_ATTRIBUTE_DEF_NAMES, 
3976                 "Grouper user data recent attribute definition names", 
3977                 "A list of attribute definition name ids and metadata in json format that are the recently used attribute definition names for a user", wasInCheckConfig);
3978             checkAttribute(userDataStem, userDataValueDef, GrouperUserDataUtils.ATTR_DEF_EXTENSION_RECENT_SUBJECTS, 
3979                 "Grouper user data recent subjects", 
3980                 "A list of attribute member ids and metadata in json format that are the recently used subjects for a user", wasInCheckConfig);
3981             checkAttribute(userDataStem, userDataValueDef, GrouperUserDataUtils.ATTR_DEF_EXTENSION_FAVORITE_ATTIRBUTE_DEFS, 
3982                 "Grouper user data favorite attribute definitions", 
3983                 "A list of attribute definition ids and metadata in json format that are the favorites for a user", wasInCheckConfig);
3984             checkAttribute(userDataStem, userDataValueDef, GrouperUserDataUtils.ATTR_DEF_EXTENSION_RECENT_ATTIRBUTE_DEFS, 
3985                 "Grouper user data recent attribute definitions", 
3986                 "A list of attribute definition ids and metadata in json format that are the recently used attribute definitions for a user", wasInCheckConfig);
3987             checkAttribute(userDataStem, userDataValueDef, GrouperUserDataUtils.ATTR_DEF_EXTENSION_FAVORITE_ATTRIBUTE_DEF_NAMES, 
3988                 "Grouper user data favorite attribute definition names", 
3989                 "A list of attribute definition name ids and metadata in json format that are the favorites for a user", wasInCheckConfig);
3990             checkAttribute(userDataStem, userDataValueDef, GrouperUserDataUtils.ATTR_DEF_EXTENSION_RECENT_ATTRIBUTE_DEF_NAMES, 
3991                 "Grouper user data recent attribute definition names", 
3992                 "A list of attribute definition name ids and metadata in json format that are the recently used attribute definition names for a user", wasInCheckConfig);
3993             checkAttribute(userDataStem, userDataValueDef, GrouperUserDataUtils.ATTR_DEF_EXTENSION_PREFERENCES,
3994               "Grouper user data preferences",
3995               "Preferences and metadata in json format for a user", wasInCheckConfig);
3996             checkAttribute(userDataStem, userDataValueDef, GrouperUserDataUtils.ATTR_DEF_EXTENSION_VISUALIZATION_PREFS,
3997               "Grouper user data visualization preferences",
3998               "Recent options for the visualization form for a user in json format", wasInCheckConfig);
3999           }
4000           
4001         }
4002       }
4003       {
4004         String entitiesRootStemName = EntityUtils.attributeEntityStemName();
4005         
4006         Stem entitiesStem = StemFinder.findByName(grouperSession, entitiesRootStemName, false, new QueryOptions().secondLevelCache(false));
4007         if (entitiesStem == null) {
4008           entitiesStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
4009             .assignDescription("folder for built in Grouper entities attributes").assignName(entitiesRootStemName)
4010             .save();
4011         }
4012 
4013         //see if attributeDef is there
4014         String entityIdDefName = entitiesRootStemName + ":entitySubjectIdentifierDef";
4015         AttributeDef entityIdDef = new AttributeDefSave(grouperSession).assignName(entityIdDefName)
4016           .assignAttributeDefPublic(true).assignAttributeDefType(AttributeDefType.attr)
4017           .assignMultiAssignable(false).assignMultiValued(false).assignToGroup(true).assignValueType(AttributeDefValueType.string).save();
4018         
4019         Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(entityIdDef);
4020         
4021         if (GrouperConfig.retrieveConfig().propertyValueBoolean("grouper.attribute.allow.everyEntity.privileges", true)) {
4022           
4023           //this is publicly assignable and readable
4024           entityIdDef.getPrivilegeDelegate().grantPriv(SubjectFinder.findAllSubject(), AttributeDefPrivilege.ATTR_READ, false);
4025           entityIdDef.getPrivilegeDelegate().grantPriv(SubjectFinder.findAllSubject(), AttributeDefPrivilege.ATTR_UPDATE, false);
4026 
4027         }
4028         
4029         //add the only name
4030         checkAttribute(entitiesStem, entityIdDef, EntityUtils.ATTR_DEF_EXTENSION_ENTITY_SUBJECT_IDENTIFIER, "This overrides the subjectId of the entity", wasInCheckConfig);
4031         
4032       }
4033 
4034       {
4035         //are we using this hook?
4036         if (GrouperUtil.trimToEmpty(GrouperConfig.retrieveConfig().propertyValueString("hooks.membership.class")).contains(MembershipOneInFolderMaxHook.class.getName())) {
4037           MembershipOneInFolderMaxHook.initObjectsOnce(wasInCheckConfig);
4038         }
4039         
4040       }
4041       {
4042         // if ignored from change log then it should be cached if not already
4043         for (String attributeDefId : GrouperUtil.nonNull(GrouperConfig.retrieveConfig().attributeDefIdsToIgnoreChangeLogAndAudit())) {
4044           AttributeDef attributeDef = AttributeDefFinder.findByIdAsRoot(attributeDefId, false);
4045           Hib3AttributeDefDAO.attributeDefCacheAsRootIdsAndNamesAdd(attributeDef);
4046         }
4047         // if ignored from change log then it should be cached if not already
4048         for (String attributeDefNameId : GrouperUtil.nonNull(GrouperConfig.retrieveConfig().attributeDefNameIdsToIgnoreChangeLogAndAudit())) {
4049           AttributeDefName attributeDefName = AttributeDefNameFinder.findById(attributeDefNameId, false);
4050           Hib3AttributeDefNameDAO.attributeDefNameCacheAsRootIdsAndNamesAdd(attributeDefName);
4051         }
4052       }
4053       
4054       if (autoAssignTheAutoAssignAttributes) {
4055         // these need to be at the end so everything else is initted
4056         AttributeAssignResult attributeAssignResult = attributeAutoCreateDef.getAttributeDelegate().assignAttribute(attributeAutoCreateMarker);
4057         attributeAssignResult.getAttributeAssign().getAttributeValueDelegate().assignValue(autoAssignIfName.getName(), attributeAutoCreateMarker.getName());
4058         attributeAssignResult.getAttributeAssign().getAttributeValueDelegate().assignValue(autoAssignThenNames.getName(), autoAssignIfName.getName() 
4059             + ", " + autoAssignThenNames.getName());
4060       }
4061 
4062       
4063     } catch (SessionException se) {
4064       throw new RuntimeException(se);
4065     } finally {
4066       if (startedGrouperSession) {
4067         GrouperSession.stopQuietly(grouperSession);
4068       }
4069       if (!wasInCheckConfig) {
4070         inCheckConfig = false;
4071       }
4072     }
4073     
4074   }
4075 
4076   /**
4077    * get or create the legacy attribute base stem
4078    * @param grouperSession
4079    * @return the stem
4080    */
4081   public static Stem legacyAttributeBaseStem(GrouperSession grouperSession) {
4082     String legacyAttributesStemName =  GrouperConfig.retrieveConfig().propertyValueStringRequired("legacyAttribute.baseStem");
4083     Stem legacyAttributesStem = StemFinder.findByName(grouperSession, legacyAttributesStemName, false, new QueryOptions().secondLevelCache(false));
4084     if (legacyAttributesStem == null) {
4085       legacyAttributesStem = new StemSave(grouperSession).assignCreateParentStemsIfNotExist(true)
4086         .assignDescription("Folder for legacy attributes.  Do not delete.")
4087         .assignName(legacyAttributesStemName).save();
4088     }
4089     return legacyAttributesStem;
4090   }
4091   
4092 }