/**
   * Initialize the schema Manager by loading the schema LDIF files
   *
   * @param instanceLayout the instance layout
   * @throws Exception in case of any problems while extracting and writing the schema files
   */
  private void initSchemaManager(InstanceLayout instanceLayout) throws Exception {
    File schemaPartitionDirectory = new File(instanceLayout.getPartitionsDirectory(), "schema");

    // Extract the schema on disk (a brand new one) and load the registries
    if (schemaPartitionDirectory.exists()) {
      LOG.info("schema partition already exists, skipping schema extraction");
    } else {
      SchemaLdifExtractor extractor =
          new DefaultSchemaLdifExtractor(instanceLayout.getPartitionsDirectory());
      extractor.extractOrCopy();
      isSchemaPartitionFirstExtraction = true;
    }

    SchemaLoader loader = new LdifSchemaLoader(schemaPartitionDirectory);
    schemaManager = new DefaultSchemaManager(loader);

    // We have to load the schema now, otherwise we won't be able
    // to initialize the Partitions, as we won't be able to parse
    // and normalize their suffix Dn
    schemaManager.loadAllEnabled();

    List<Throwable> errors = schemaManager.getErrors();

    if (errors.size() != 0) {
      throw new Exception(I18n.err(I18n.ERR_317, Exceptions.printErrors(errors)));
    }
  }
  /**
   * adds mandatory operational attributes {@link #MANDATORY_ENTRY_ATOP_MAP} and updates all the
   * LDIF files. WARN: this method is only called for the first time when schema and config files
   * are bootstrapped afterwards it is the responsibility of the user to ensure correctness of LDIF
   * files if modified by hand
   *
   * <p>Note: we do these modifications explicitly cause we have no idea if each entry's LDIF file
   * has the correct values for all these mandatory attributes
   *
   * @param partition instance of the partition Note: should only be those which are loaded before
   *     starting the DirectoryService
   * @param dirService the DirectoryService instance
   * @throws Exception
   */
  public void updateMandatoryOpAttributes(Partition partition, DirectoryService dirService)
      throws Exception {
    CoreSession session = dirService.getAdminSession();

    String adminDn = session.getEffectivePrincipal().getName();

    ExprNode filter = new PresenceNode(SchemaConstants.OBJECT_CLASS_AT);

    AttributeType uuidAtT =
        schemaManager.lookupAttributeTypeRegistry(SchemaConstants.ENTRY_UUID_AT);
    AttributeType atTypeT = schemaManager.lookupAttributeTypeRegistry(SchemaConstants.ENTRY_CSN_AT);
    AttributeType creatorAtT =
        schemaManager.lookupAttributeTypeRegistry(SchemaConstants.CREATORS_NAME_AT);
    AttributeType createdTimeAtT =
        schemaManager.lookupAttributeTypeRegistry(SchemaConstants.CREATE_TIMESTAMP_AT);

    //        HashSet<AttributeTypeOptions> options = new HashSet<AttributeTypeOptions>(
    // MANDATORY_ENTRY_ATOP_MAP.values());
    /*


            AttributeType at;
            at
            //
            String id = SchemaUtils.stripOptions( returnAttribute );
            Set<String> options = SchemaUtils.getOptions( returnAttribute );

            AttributeType attributeType = session.getDirectoryService()
                .getSchemaManager().lookupAttributeTypeRegistry( id );
            AttributeTypeOptions attrOptions = new AttributeTypeOptions( attributeType, options );
    //

            EntryFilteringCursor cursor = session.search( partition.getSuffixDn(), SearchScope.SUBTREE, filter,
                AliasDerefMode.NEVER_DEREF_ALIASES, new HashSet<AttributeTypeOptions>( MANDATORY_ENTRY_ATOP_MAP.values() ) );
            cursor.beforeFirst();
    		 */
    EntryFilteringCursor cursor =
        session.search(
            partition.getSuffixDn(),
            SearchScope.SUBTREE,
            filter,
            AliasDerefMode.NEVER_DEREF_ALIASES,
            SchemaConstants.OBJECT_CLASS_AT_OID,
            SchemaConstants.ENTRY_UUID_AT_OID,
            SchemaConstants.ENTRY_CSN_AT_OID,
            SchemaConstants.CREATORS_NAME_AT_OID,
            SchemaConstants.CREATORS_NAME_AT_OID);
    cursor.beforeFirst();

    List<Modification> mods = new ArrayList<Modification>();

    while (cursor.next()) {
      Entry entry = cursor.get();

      Attribute uuidAt = entry.get(uuidAtT);
      String uuid = (uuidAt == null ? null : uuidAt.getString());

      if (!uuidChecker.isValidSyntax(uuid)) {
        uuidAt = new DefaultAttribute(uuidAtT, UUID.randomUUID().toString());
      }

      Modification uuidMod =
          new DefaultModification(ModificationOperation.REPLACE_ATTRIBUTE, uuidAt);
      mods.add(uuidMod);

      Attribute csnAt = entry.get(atTypeT);
      String csn = (csnAt == null ? null : csnAt.getString());

      if (!csnChecker.isValidSyntax(csn)) {
        csnAt = new DefaultAttribute(atTypeT, dirService.getCSN().toString());
      }

      Modification csnMod = new DefaultModification(ModificationOperation.REPLACE_ATTRIBUTE, csnAt);
      mods.add(csnMod);

      Attribute creatorAt = entry.get(creatorAtT);
      String creator = (creatorAt == null ? "" : creatorAt.getString().trim());

      if ((creator.length() == 0) || (!Dn.isValid(creator))) {
        creatorAt = new DefaultAttribute(creatorAtT, adminDn);
      }

      Modification creatorMod =
          new DefaultModification(ModificationOperation.REPLACE_ATTRIBUTE, creatorAt);
      mods.add(creatorMod);

      Attribute createdTimeAt = entry.get(createdTimeAtT);
      String createdTime = (createdTimeAt == null ? null : createdTimeAt.getString());

      if (!timeChecker.isValidSyntax(createdTime)) {
        createdTimeAt = new DefaultAttribute(createdTimeAtT, DateUtils.getGeneralizedTime());
      }

      Modification createdMod =
          new DefaultModification(ModificationOperation.REPLACE_ATTRIBUTE, createdTimeAt);
      mods.add(createdMod);

      if (!mods.isEmpty()) {
        LOG.debug(
            "modifying the entry {} after adding missing manadatory operational attributes",
            entry.getDn());
        ModifyOperationContext modifyContext = new ModifyOperationContext(session);
        modifyContext.setEntry(entry);
        modifyContext.setDn(entry.getDn());
        modifyContext.setModItems(mods);
        partition.modify(modifyContext);
      }

      mods.clear();
    }

    cursor.close();
  }
  /** {@inheritDoc} */
  public void init(String name) throws Exception {
    if ((directoryService != null) && directoryService.isStarted()) {
      return;
    }

    directoryService.setInstanceId(name);

    // instance layout
    InstanceLayout instanceLayout =
        new InstanceLayout(System.getProperty("java.io.tmpdir") + "/server-work-" + name);
    if (instanceLayout.getInstanceDirectory().exists()) {
      try {
        FileUtils.deleteDirectory(instanceLayout.getInstanceDirectory());
      } catch (IOException e) {
        LOG.warn(
            "couldn't delete the instance directory before initializing the DirectoryService", e);
      }
    }
    directoryService.setInstanceLayout(instanceLayout);

    // EhCache in disabled-like-mode
    Configuration ehCacheConfig = new Configuration();
    CacheConfiguration defaultCache =
        new CacheConfiguration("default", 1)
            .eternal(false)
            .timeToIdleSeconds(30)
            .timeToLiveSeconds(30)
            .overflowToDisk(false);
    ehCacheConfig.addDefaultCache(defaultCache);
    CacheService cacheService = new CacheService(new CacheManager(ehCacheConfig));
    directoryService.setCacheService(cacheService);

    // Init the schema
    // SchemaLoader loader = new SingleLdifSchemaLoader();
    SchemaLoader loader = new JarLdifSchemaLoader();
    SchemaManager schemaManager = new DefaultSchemaManager(loader);
    schemaManager.loadAllEnabled();
    ComparatorRegistry comparatorRegistry = schemaManager.getComparatorRegistry();
    for (LdapComparator<?> comparator : comparatorRegistry) {
      if (comparator instanceof NormalizingComparator) {
        ((NormalizingComparator) comparator).setOnServer();
      }
    }
    directoryService.setSchemaManager(schemaManager);
    InMemorySchemaPartition inMemorySchemaPartition = new InMemorySchemaPartition(schemaManager);

    SchemaPartition schemaPartition = new SchemaPartition(schemaManager);
    schemaPartition.setWrappedPartition(inMemorySchemaPartition);
    directoryService.setSchemaPartition(schemaPartition);
    List<Throwable> errors = schemaManager.getErrors();
    if (errors.size() != 0) {
      throw new Exception(I18n.err(I18n.ERR_317, Exceptions.printErrors(errors)));
    }

    // Init system partition
    Partition systemPartition =
        partitionFactory.createPartition(
            directoryService.getSchemaManager(),
            "system",
            ServerDNConstants.SYSTEM_DN,
            500,
            new File(directoryService.getInstanceLayout().getPartitionsDirectory(), "system"));
    systemPartition.setSchemaManager(directoryService.getSchemaManager());
    partitionFactory.addIndex(systemPartition, SchemaConstants.OBJECT_CLASS_AT, 100);
    directoryService.setSystemPartition(systemPartition);

    directoryService.startup();
  }