/** {@inheritDoc} */
  public ConfigChangeResult applyConfigurationAdd(LogRotationPolicyCfg config) {
    // Default result code.
    ResultCode resultCode = ResultCode.SUCCESS;
    boolean adminActionRequired = false;
    ArrayList<Message> messages = new ArrayList<Message>();

    try {
      RotationPolicy rotationPolicy = getRotationPolicy(config);

      DirectoryServer.registerRotationPolicy(config.dn(), rotationPolicy);
    } catch (ConfigException e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      messages.add(e.getMessageObject());
      resultCode = DirectoryServer.getServerErrorResultCode();
    } catch (Exception e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }

      messages.add(
          ERR_CONFIG_ROTATION_POLICY_CANNOT_CREATE_POLICY.get(
              String.valueOf(config.dn().toString()), stackTraceToSingleLineString(e)));
      resultCode = DirectoryServer.getServerErrorResultCode();
    }

    return new ConfigChangeResult(resultCode, adminActionRequired, messages);
  }
  /**
   * Generates an entry for a backup directory based on the provided DN. The DN must contain an RDN
   * component that specifies the path to the backup directory, and that directory must exist and be
   * a valid backup directory.
   *
   * @param entryDN The DN of the backup directory entry to retrieve.
   * @return The requested backup directory entry.
   * @throws DirectoryException If the specified directory does not exist or is not a valid backup
   *     directory, or if the DN does not specify any backup directory.
   */
  private Entry getBackupDirectoryEntry(DN entryDN) throws DirectoryException {
    // Make sure that the DN specifies a backup directory.
    AttributeType t = DirectoryServer.getAttributeType(ATTR_BACKUP_DIRECTORY_PATH, true);
    AttributeValue v = entryDN.getRDN().getAttributeValue(t);
    if (v == null) {
      Message message = ERR_BACKUP_DN_DOES_NOT_SPECIFY_DIRECTORY.get(String.valueOf(entryDN));
      throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message, backupBaseDN, null);
    }

    // Get a handle to the backup directory and the information that it
    // contains.
    BackupDirectory backupDirectory;
    try {
      backupDirectory = BackupDirectory.readBackupDirectoryDescriptor(v.getValue().toString());
    } catch (ConfigException ce) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, ce);
      }

      Message message =
          ERR_BACKUP_INVALID_BACKUP_DIRECTORY.get(String.valueOf(entryDN), ce.getMessage());
      throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
    } catch (Exception e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }

      Message message = ERR_BACKUP_ERROR_GETTING_BACKUP_DIRECTORY.get(getExceptionMessage(e));
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message);
    }

    // Construct the backup directory entry to return.
    LinkedHashMap<ObjectClass, String> ocMap = new LinkedHashMap<ObjectClass, String>(2);
    ocMap.put(DirectoryServer.getTopObjectClass(), OC_TOP);

    ObjectClass backupDirOC = DirectoryServer.getObjectClass(OC_BACKUP_DIRECTORY, true);
    ocMap.put(backupDirOC, OC_BACKUP_DIRECTORY);

    LinkedHashMap<AttributeType, List<Attribute>> opAttrs =
        new LinkedHashMap<AttributeType, List<Attribute>>(0);
    LinkedHashMap<AttributeType, List<Attribute>> userAttrs =
        new LinkedHashMap<AttributeType, List<Attribute>>(3);

    ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
    attrList.add(Attributes.create(t, v));
    userAttrs.put(t, attrList);

    t = DirectoryServer.getAttributeType(ATTR_BACKUP_BACKEND_DN, true);
    attrList = new ArrayList<Attribute>(1);
    attrList.add(
        Attributes.create(
            t, AttributeValues.create(t, backupDirectory.getConfigEntryDN().toString())));
    userAttrs.put(t, attrList);

    Entry e = new Entry(entryDN, ocMap, userAttrs, opAttrs);
    e.processVirtualAttributes();
    return e;
  }
  /**
   * Closes this connection handler so that it will no longer accept new client connections. It may
   * or may not disconnect existing client connections based on the provided flag.
   *
   * @param stopRegistry Indicates if the RMI registry should be stopped
   */
  public void finalizeConnectionHandler(boolean stopRegistry) {
    try {
      if (jmxRmiConnectorNoClientCertificate != null) {
        jmxRmiConnectorNoClientCertificate.stop();
      }
      if (jmxRmiConnectorClientCertificate != null) {
        jmxRmiConnectorClientCertificate.stop();
      }
    } catch (Exception e) {
      TRACER.debugCaught(DebugLogLevel.ERROR, e);
    }

    jmxRmiConnectorNoClientCertificate = null;
    jmxRmiConnectorClientCertificate = null;

    //
    // Unregister connectors and stop them.
    try {
      ObjectName name = new ObjectName(jmxRmiConnectorNoClientCertificateName);
      if (mbs.isRegistered(name)) {
        mbs.unregisterMBean(name);
      }
      if (jmxRmiConnectorNoClientCertificate != null) {
        jmxRmiConnectorNoClientCertificate.stop();
      }

      // TODO: unregister the connector with SSL client authen
      //      name = new ObjectName(jmxRmiConnectorClientCertificateName);
      //      if (mbs.isRegistered(name))
      //      {
      //        mbs.unregisterMBean(name);
      //      }
      //      jmxRmiConnectorClientCertificate.stop() ;
    } catch (Exception e) {
      // TODO Log an error message
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
    }

    if (stopRegistry) {
      //
      // Close the socket
      try {
        if (rmiSsf != null) rmiSsf.close();
      } catch (IOException e) {
        // TODO Log an error message
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      }
      registry = null;
    }
  }
  /** {@inheritDoc} */
  @Override()
  public void finalizeBackend() {
    // Deregister as a change listener.
    cfg.removeLocalDBChangeListener(this);

    // Deregister our base DNs.
    for (DN dn : rootContainer.getBaseDNs()) {
      try {
        DirectoryServer.deregisterBaseDN(dn);
      } catch (Exception e) {
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      }
    }

    DirectoryServer.deregisterMonitorProvider(rootContainerMonitor);
    DirectoryServer.deregisterMonitorProvider(diskMonitor);

    // We presume the server will prevent more operations coming into this
    // backend, but there may be existing operations already in the
    // backend. We need to wait for them to finish.
    waitUntilQuiescent();

    // Close the database.
    try {
      rootContainer.close();
      rootContainer = null;
    } catch (DatabaseException e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_JEB_DATABASE_EXCEPTION.get(e.getMessage());
      logError(message);
    }

    // Checksum this db environment and register its offline state id/checksum.
    DirectoryServer.registerOfflineBackendStateID(this.getBackendID(), checksumDbEnv());

    // Deregister the alert generator.
    DirectoryServer.deregisterAlertGenerator(this);

    // Make sure the thread counts are zero for next initialization.
    threadTotalCount.set(0);
    threadWriteCount.set(0);

    // Log an informational message.
    Message message = NOTE_BACKEND_OFFLINE.get(cfg.getBackendId());
    logError(message);
  }
  /**
   * Verify the integrity of the backend instance.
   *
   * @param verifyConfig The verify configuration.
   * @param statEntry Optional entry to save stats into.
   * @return The error count.
   * @throws ConfigException If an unrecoverable problem arises during initialization.
   * @throws InitializationException If a problem occurs during initialization that is not related
   *     to the server configuration.
   * @throws DirectoryException If a Directory Server error occurs.
   */
  public long verifyBackend(VerifyConfig verifyConfig, Entry statEntry)
      throws InitializationException, ConfigException, DirectoryException {
    // If the backend already has the root container open, we must use the same
    // underlying root container
    boolean openRootContainer = rootContainer == null;
    long errorCount = 0;

    try {
      if (openRootContainer) {
        EnvironmentConfig envConfig = ConfigurableEnvironment.parseConfigEntry(cfg);

        envConfig.setReadOnly(true);
        envConfig.setAllowCreate(false);
        envConfig.setTransactional(false);
        envConfig.setConfigParam("je.env.isLocking", "true");
        envConfig.setConfigParam("je.env.runCheckpointer", "true");

        rootContainer = initializeRootContainer(envConfig);
      }

      VerifyJob verifyJob = new VerifyJob(verifyConfig);
      errorCount = verifyJob.verifyBackend(rootContainer, statEntry);
    } catch (DatabaseException e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      throw createDirectoryException(e);
    } catch (JebException e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      throw new DirectoryException(
          DirectoryServer.getServerErrorResultCode(), e.getMessageObject());
    } finally {
      // If a root container was opened in this method as read only, close it
      // to leave the backend in the same state.
      if (openRootContainer && rootContainer != null) {
        try {
          rootContainer.close();
          rootContainer = null;
        } catch (DatabaseException e) {
          if (debugEnabled()) {
            TRACER.debugCaught(DebugLogLevel.ERROR, e);
          }
        }
      }
    }
    return errorCount;
  }
  /** {@inheritDoc} */
  @Override()
  public void search(SearchOperation searchOperation)
      throws DirectoryException, CanceledOperationException {
    readerBegin();

    EntryContainer ec;
    if (rootContainer != null) {
      ec = rootContainer.getEntryContainer(searchOperation.getBaseDN());
    } else {
      Message message = ERR_ROOT_CONTAINER_NOT_INITIALIZED.get(getBackendID());
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message);
    }
    ec.sharedLock.lock();

    try {
      ec.search(searchOperation);
    } catch (DatabaseException e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      throw createDirectoryException(e);
    } finally {
      ec.sharedLock.unlock();
      readerEnd();
    }
  }
  /** Activates the RMI Connectors. It starts the secure connectors. */
  public void initialize() {
    try {
      //
      // start the common registry
      startCommonRegistry();

      //
      // start the RMI connector (SSL + server authentication)
      startConnectorNoClientCertificate();

      //
      // start the RMI connector (SSL + server authentication +
      // client authentication + identity given part SASL/PLAIN)
      // TODO startConnectorClientCertificate(clientConnection);

    } catch (Exception e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }

      throw new RuntimeException("Error while starting the RMI module : " + e.getMessage());
    }

    if (debugEnabled()) {
      TRACER.debugVerbose("RMI module started");
    }
  }
  /** {@inheritDoc} */
  @Override()
  public void replaceEntry(Entry oldEntry, Entry newEntry, ModifyOperation modifyOperation)
      throws DirectoryException, CanceledOperationException {
    checkDiskSpace(modifyOperation);
    writerBegin();

    DN entryDN = newEntry.getDN();
    EntryContainer ec;
    if (rootContainer != null) {
      ec = rootContainer.getEntryContainer(entryDN);
    } else {
      Message message = ERR_ROOT_CONTAINER_NOT_INITIALIZED.get(getBackendID());
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message);
    }

    ec.sharedLock.lock();

    try {
      ec.replaceEntry(oldEntry, newEntry, modifyOperation);
    } catch (DatabaseException e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      throw createDirectoryException(e);
    } finally {
      ec.sharedLock.unlock();
      writerEnd();
    }
  }
  /** {@inheritDoc} */
  @Override()
  public long numSubordinates(DN entryDN, boolean subtree) throws DirectoryException {
    EntryContainer ec;
    if (rootContainer != null) {
      ec = rootContainer.getEntryContainer(entryDN);
    } else {
      Message message = ERR_ROOT_CONTAINER_NOT_INITIALIZED.get(getBackendID());
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message);
    }

    if (ec == null) {
      return -1;
    }

    readerBegin();
    ec.sharedLock.lock();
    try {
      long count = ec.getNumSubordinates(entryDN, subtree);
      if (count == Long.MAX_VALUE) {
        // The index entry limit has exceeded and there is no count maintained.
        return -1;
      }
      return count;
    } catch (DatabaseException e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      throw createDirectoryException(e);
    } finally {
      ec.sharedLock.unlock();
      readerEnd();
    }
  }
  /** {@inheritDoc} */
  @Override()
  public Entry getEntry(DN entryDN) throws DirectoryException {
    readerBegin();

    EntryContainer ec;
    if (rootContainer != null) {
      ec = rootContainer.getEntryContainer(entryDN);
    } else {
      Message message = ERR_ROOT_CONTAINER_NOT_INITIALIZED.get(getBackendID());
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message);
    }

    ec.sharedLock.lock();
    Entry entry;
    try {
      entry = ec.getEntry(entryDN);
    } catch (DatabaseException e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      throw createDirectoryException(e);
    } finally {
      ec.sharedLock.unlock();
      readerEnd();
    }

    return entry;
  }
  /** {@inheritDoc} */
  @Override()
  public DynamicGroup newInstance(Entry groupEntry) throws DirectoryException {
    ensureNotNull(groupEntry);

    // Get the memberURL attribute from the entry, if there is one, and parse
    // out the LDAP URLs that it contains.
    LinkedHashSet<LDAPURL> memberURLs = new LinkedHashSet<LDAPURL>();
    AttributeType memberURLType = DirectoryConfig.getAttributeType(ATTR_MEMBER_URL_LC, true);
    List<Attribute> attrList = groupEntry.getAttribute(memberURLType);
    if (attrList != null) {
      for (Attribute a : attrList) {
        for (AttributeValue v : a) {
          try {
            memberURLs.add(LDAPURL.decode(v.getValue().toString(), true));
          } catch (DirectoryException de) {
            if (debugEnabled()) {
              TRACER.debugCaught(DebugLogLevel.ERROR, de);
            }

            Message message =
                ERR_DYNAMICGROUP_CANNOT_DECODE_MEMBERURL.get(
                    v.getValue().toString(),
                    String.valueOf(groupEntry.getDN()),
                    de.getMessageObject());
            ErrorLogger.logError(message);
          }
        }
      }
    }

    return new DynamicGroup(groupEntry.getDN(), memberURLs);
  }
  /**
   * This method will attempt to checksum the current JE db environment by computing the Adler-32
   * checksum on the latest JE log file available.
   *
   * @return The checksum of JE db environment or zero if checksum failed.
   */
  private long checksumDbEnv() {

    File parentDirectory = getFileForPath(cfg.getDBDirectory());
    File backendDirectory = new File(parentDirectory, cfg.getBackendId());

    List<File> jdbFiles = new ArrayList<File>();
    if (backendDirectory.isDirectory()) {
      jdbFiles =
          Arrays.asList(
              backendDirectory.listFiles(
                  new FilenameFilter() {
                    public boolean accept(File dir, String name) {
                      return name.endsWith(".jdb");
                    }
                  }));
    }

    if (!jdbFiles.isEmpty()) {
      Collections.sort(jdbFiles, Collections.reverseOrder());
      FileInputStream fis = null;
      try {
        fis = new FileInputStream(jdbFiles.get(0).toString());
        CheckedInputStream cis = new CheckedInputStream(fis, new Adler32());
        byte[] tempBuf = new byte[8192];
        while (cis.read(tempBuf) >= 0) {}

        return cis.getChecksum().getValue();
      } catch (Exception e) {
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      } finally {
        if (fis != null) {
          try {
            fis.close();
          } catch (Exception e) {
            if (debugEnabled()) {
              TRACER.debugCaught(DebugLogLevel.ERROR, e);
            }
          }
        }
      }
    }

    return 0;
  }
 /**
  * Getter for the serviceID field.
  *
  * @return The service ID.
  */
 public String getServiceID() {
   try {
     return this.draftCNDbCursor.currentServiceID();
   } catch (Exception e) {
     TRACER.debugCaught(DebugLogLevel.ERROR, e);
     return null;
   }
 }
 /**
  * Getter for the replication change number field.
  *
  * @return The replication change number field.
  */
 public ChangeNumber getChangeNumber() {
   try {
     ChangeNumber cn = this.draftCNDbCursor.currentChangeNumber();
     return cn;
   } catch (Exception e) {
     TRACER.debugCaught(DebugLogLevel.ERROR, e);
     return null;
   }
 }
  /**
   * Process all ACIs under the "cn=config" naming context and adds them to the ACI list cache. It
   * also logs messages about the number of ACIs added to the cache. This method is called once at
   * startup. It will put the server in lockdown mode if needed.
   *
   * @throws InitializationException If there is an error searching for the ACIs in the naming
   *     context.
   */
  private void processConfigAcis() throws InitializationException {
    LinkedHashSet<String> requestAttrs = new LinkedHashSet<String>(1);
    requestAttrs.add("aci");
    LinkedList<Message> failedACIMsgs = new LinkedList<Message>();
    InternalClientConnection conn = InternalClientConnection.getRootConnection();

    ConfigHandler configBackend = DirectoryServer.getConfigHandler();
    for (DN baseDN : configBackend.getBaseDNs()) {
      try {
        if (!configBackend.entryExists(baseDN)) {
          continue;
        }
      } catch (Exception e) {
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }

        // FIXME -- Is there anything that we need to do here?
        continue;
      }

      try {
        InternalSearchOperation internalSearch =
            new InternalSearchOperation(
                conn,
                InternalClientConnection.nextOperationID(),
                InternalClientConnection.nextMessageID(),
                null,
                baseDN,
                SearchScope.WHOLE_SUBTREE,
                DereferencePolicy.NEVER_DEREF_ALIASES,
                0,
                0,
                false,
                SearchFilter.createFilterFromString("aci=*"),
                requestAttrs,
                null);
        LocalBackendSearchOperation localSearch = new LocalBackendSearchOperation(internalSearch);

        configBackend.search(localSearch);

        if (!internalSearch.getSearchEntries().isEmpty()) {
          int validAcis = aciList.addAci(internalSearch.getSearchEntries(), failedACIMsgs);
          if (!failedACIMsgs.isEmpty()) {
            aciListenerMgr.logMsgsSetLockDownMode(failedACIMsgs);
          }
          Message message =
              INFO_ACI_ADD_LIST_ACIS.get(Integer.toString(validAcis), String.valueOf(baseDN));
          logError(message);
        }
      } catch (Exception e) {
        Message message = INFO_ACI_HANDLER_FAIL_PROCESS_ACI.get();
        throw new InitializationException(message, e);
      }
    }
  }
  /** Closes this LDAP reader and the underlying socket. */
  public void close() {
    try {
      asn1Reader.close();
    } catch (Exception e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
    }

    if (socket != null) {
      try {
        socket.close();
      } catch (Exception e) {
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      }
    }
  }
 /**
  * Wait until there are no more threads accessing the database. It is assumed that new threads
  * have been prevented from entering the database at the time this method is called.
  */
 private void waitUntilQuiescent() {
   while (threadTotalCount.get() > 0) {
     // Still have threads in the database so sleep a little
     try {
       Thread.sleep(500);
     } catch (InterruptedException e) {
       if (debugEnabled()) {
         TRACER.debugCaught(DebugLogLevel.ERROR, e);
       }
     }
   }
 }
  /** {@inheritDoc} */
  @Override
  public void finalizeBackend() {
    super.finalizeBackend();
    currentConfig.removeBackupChangeListener(this);

    try {
      DirectoryServer.deregisterBaseDN(backupBaseDN);
    } catch (Exception e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
    }
  }
  /**
   * Starts the common RMI registry. In order to provide RMI stub for remote client, the JMX RMI
   * connector should be register into an RMI registry. Each server will maintain its own private
   * one.
   *
   * @throws Exception if the registry cannot be started
   */
  private void startCommonRegistry() throws Exception {
    int registryPort = jmxConnectionHandler.getListenPort();

    //
    // create our local RMI registry if it does not exist already
    if (debugEnabled()) {
      TRACER.debugVerbose("start or reach an RMI registry on port %d", registryPort);
    }
    try {
      //
      // TODO Not yet implemented: If the host has several interfaces
      if (registry == null) {
        rmiSsf = new OpendsRmiServerSocketFactory();
        registry = LocateRegistry.createRegistry(registryPort, null, rmiSsf);
      }
    } catch (RemoteException re) {
      //
      // is the registry already created ?
      if (debugEnabled()) {
        TRACER.debugWarning("cannot create the RMI registry -> already done ?");
      }
      try {
        //
        // get a 'remote' reference on the registry
        Registry reg = LocateRegistry.getRegistry(registryPort);

        //
        // 'ping' the registry
        reg.list();
        registry = reg;
      } catch (Exception e) {
        if (debugEnabled()) {
          //
          // no 'valid' registry found on the specified port
          TRACER.debugError("exception thrown while pinging the RMI registry");

          //
          // throw the original exception
          TRACER.debugCaught(DebugLogLevel.ERROR, re);
        }
        throw re;
      }

      //
      // here the registry is ok even though
      // it was not created by this call
      if (debugEnabled()) {
        TRACER.debugWarning("RMI was registry already started");
      }
    }
  }
  /** {@inheritDoc} */
  @Override()
  public long getEntryCount() {
    if (rootContainer != null) {
      try {
        return rootContainer.getEntryCount();
      } catch (Exception e) {
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      }
    }

    return -1;
  }
  /**
   * A utility method which may be used by implementations in order to obtain the value of the
   * specified attribute from the provided entry as a time in generalized time format.
   *
   * @param entry The entry whose attribute is to be parsed as a boolean.
   * @param attributeType The attribute type whose value should be parsed as a generalized time
   *     value.
   * @return The requested time, or -1 if it could not be determined.
   * @throws DirectoryException If a problem occurs while attempting to decode the value as a
   *     generalized time.
   */
  protected static final long getGeneralizedTime(
      final Entry entry, final AttributeType attributeType) throws DirectoryException {
    long timeValue = -1;

    final List<Attribute> attrList = entry.getAttribute(attributeType);
    if (attrList != null) {
      for (final Attribute a : attrList) {
        if (a.isEmpty()) {
          continue;
        }

        final AttributeValue v = a.iterator().next();
        try {
          timeValue = GeneralizedTimeSyntax.decodeGeneralizedTimeValue(v.getNormalizedValue());
        } catch (final Exception e) {
          if (debugEnabled()) {
            TRACER.debugCaught(DebugLogLevel.ERROR, e);

            TRACER.debugWarning(
                "Unable to decode value %s for attribute %s " + "in user entry %s: %s",
                v.getValue().toString(),
                attributeType.getNameOrOID(),
                entry.getDN().toString(),
                stackTraceToSingleLineString(e));
          }

          final Message message =
              ERR_PWPSTATE_CANNOT_DECODE_GENERALIZED_TIME.get(
                  v.getValue().toString(),
                  attributeType.getNameOrOID(),
                  entry.getDN().toString(),
                  String.valueOf(e));
          throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message, e);
        }
        break;
      }
    }

    if (timeValue == -1) {
      if (debugEnabled()) {
        TRACER.debugInfo(
            "Returning -1 because attribute %s does not " + "exist in user entry %s",
            attributeType.getNameOrOID(), entry.getDN().toString());
      }
    }
    // FIXME: else to be consistent...

    return timeValue;
  }
 private RootContainer initializeRootContainer(EnvironmentConfig envConfig)
     throws ConfigException, InitializationException {
   // Open the database environment
   try {
     RootContainer rc = new RootContainer(this, cfg);
     rc.open(envConfig);
     return rc;
   } catch (DatabaseException e) {
     if (debugEnabled()) {
       TRACER.debugCaught(DebugLogLevel.ERROR, e);
     }
     Message message = ERR_JEB_OPEN_ENV_FAIL.get(e.getMessage());
     throw new InitializationException(message, e);
   }
 }
  /** {@inheritDoc} */
  @Override()
  public boolean hasValue(Entry entry, VirtualAttributeRule rule) {
    Backend backend = DirectoryServer.getBackend(entry.getDN());

    try {
      ConditionResult ret = backend.hasSubordinates(entry.getDN());
      return ret != null && ret != ConditionResult.UNDEFINED;
    } catch (DirectoryException de) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, de);
      }

      return false;
    }
  }
  /**
   * Indicates whether the provided value is acceptable for use in an attribute with this syntax. If
   * it is not, then the reason may be appended to the provided buffer.
   *
   * @param value The value for which to make the determination.
   * @param invalidReason The buffer to which the invalid reason should be appended.
   * @return <CODE>true</CODE> if the provided value is acceptable for use with this syntax, or
   *     <CODE>false</CODE> if not.
   */
  @Override
  public boolean valueIsAcceptable(ByteSequence value, MessageBuilder invalidReason) {
    // We'll use the decodeAttributeType method to determine if the value is
    // acceptable.
    try {
      decodeLDAPSyntax(value, DirectoryServer.getSchema(), true);
      return true;
    } catch (DirectoryException de) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, de);
      }

      invalidReason.append(de.getMessageObject());
      return false;
    }
  }
 /**
  * Process all global ACI attribute types found in the configuration entry and adds them to that
  * ACI list cache. It also logs messages about the number of ACI attribute types added to the
  * cache. This method is called once at startup. It also will put the server into lockdown mode if
  * needed.
  *
  * @param configuration The config handler containing the ACI configuration information.
  * @throws InitializationException If there is an error reading the global ACIs from the
  *     configuration entry.
  */
 private void processGlobalAcis(DseeCompatAccessControlHandlerCfg configuration)
     throws InitializationException {
   SortedSet<Aci> globalAcis = configuration.getGlobalACI();
   try {
     if (globalAcis != null) {
       aciList.addAci(DN.nullDN(), globalAcis);
       Message message = INFO_ACI_ADD_LIST_GLOBAL_ACIS.get(Integer.toString(globalAcis.size()));
       logError(message);
     }
   } catch (Exception e) {
     if (debugEnabled()) {
       TRACER.debugCaught(DebugLogLevel.ERROR, e);
     }
     Message message =
         INFO_ACI_HANDLER_FAIL_PROCESS_GLOBAL_ACI.get(String.valueOf(configuration.dn()));
     throw new InitializationException(message, e);
   }
 }
  /** {@inheritDoc} */
  @Override()
  public Set<AttributeValue> getValues(Entry entry, VirtualAttributeRule rule) {
    Backend backend = DirectoryServer.getBackend(entry.getDN());

    try {
      ConditionResult ret = backend.hasSubordinates(entry.getDN());
      if (ret != null && ret != ConditionResult.UNDEFINED) {
        AttributeValue value =
            AttributeValues.create(
                ByteString.valueOf(ret.toString()), ByteString.valueOf(ret.toString()));
        return Collections.singleton(value);
      }
    } catch (DirectoryException de) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, de);
      }
    }

    return Collections.emptySet();
  }
  /** {@inheritDoc} */
  @Override()
  public boolean isIndexed(AttributeType attributeType, IndexType indexType) {
    try {
      EntryContainer ec = rootContainer.getEntryContainer(baseDNs[0]);
      AttributeIndex ai = ec.getAttributeIndex(attributeType);
      if (ai == null) {
        return false;
      }

      Set<LocalDBIndexCfgDefn.IndexType> indexTypes = ai.getConfiguration().getIndexType();
      switch (indexType) {
        case PRESENCE:
          return indexTypes.contains(LocalDBIndexCfgDefn.IndexType.PRESENCE);

        case EQUALITY:
          return indexTypes.contains(LocalDBIndexCfgDefn.IndexType.EQUALITY);

        case SUBSTRING:
        case SUBINITIAL:
        case SUBANY:
        case SUBFINAL:
          return indexTypes.contains(LocalDBIndexCfgDefn.IndexType.SUBSTRING);

        case GREATER_OR_EQUAL:
        case LESS_OR_EQUAL:
          return indexTypes.contains(LocalDBIndexCfgDefn.IndexType.ORDERING);

        case APPROXIMATE:
          return indexTypes.contains(LocalDBIndexCfgDefn.IndexType.APPROXIMATE);

        default:
          return false;
      }
    } catch (Exception e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }

      return false;
    }
  }
  /**
   * Returns {@code true} if this authentication policy state is associated with a user whose
   * account has been administratively disabled.
   *
   * <p>The default implementation is use the value of the "ds-pwp-account-disable" attribute in the
   * user's entry.
   *
   * @return {@code true} if this authentication policy state is associated with a user whose
   *     account has been administratively disabled.
   */
  public boolean isDisabled() {
    final AttributeType type = DirectoryServer.getAttributeType(OP_ATTR_ACCOUNT_DISABLED, true);
    try {
      isDisabled = getBoolean(userEntry, type);
    } catch (final Exception e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }

      isDisabled = ConditionResult.TRUE;
      if (debugEnabled()) {
        TRACER.debugWarning(
            "User %s is considered administratively "
                + "disabled because an error occurred while "
                + "attempting to make the determination: %s.",
            userEntry.getDN().toString(), stackTraceToSingleLineString(e));
      }

      return true;
    }

    if (isDisabled == ConditionResult.UNDEFINED) {
      isDisabled = ConditionResult.FALSE;
      if (debugEnabled()) {
        TRACER.debugInfo(
            "User %s is not administratively disabled since "
                + "the attribute \"%s\" is not present in the entry.",
            userEntry.getDN().toString(), OP_ATTR_ACCOUNT_DISABLED);
      }
      return false;
    }

    if (debugEnabled()) {
      TRACER.debugInfo(
          "User %s %s administratively disabled.",
          userEntry.getDN().toString(), ((isDisabled == ConditionResult.TRUE) ? " is" : " is not"));
    }

    return isDisabled == ConditionResult.TRUE;
  }
  /** {@inheritDoc} */
  @Override()
  public void renameEntry(DN currentDN, Entry entry, ModifyDNOperation modifyDNOperation)
      throws DirectoryException, CanceledOperationException {
    checkDiskSpace(modifyDNOperation);
    writerBegin();

    EntryContainer currentContainer;
    if (rootContainer != null) {
      currentContainer = rootContainer.getEntryContainer(currentDN);
    } else {
      Message message = ERR_ROOT_CONTAINER_NOT_INITIALIZED.get(getBackendID());
      throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message);
    }

    EntryContainer container = rootContainer.getEntryContainer(entry.getDN());

    if (currentContainer != container) {
      // FIXME: No reason why we cannot implement a move between containers
      // since the containers share the same database environment.
      Message msg = WARN_JEB_FUNCTION_NOT_SUPPORTED.get();
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, msg);
    }

    currentContainer.sharedLock.lock();
    try {
      currentContainer.renameEntry(currentDN, entry, modifyDNOperation);
    } catch (DatabaseException e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      throw createDirectoryException(e);
    } finally {
      currentContainer.sharedLock.unlock();
      writerEnd();
    }
  }
  /**
   * Handles any controls contained in the request.
   *
   * @throws DirectoryException If there is a problem with any of the request controls.
   */
  private void handleRequestControls() throws DirectoryException {
    LocalBackendWorkflowElement.removeAllDisallowedControls(baseDN, this);

    List<Control> requestControls = getRequestControls();
    if (requestControls != null && !requestControls.isEmpty()) {
      for (Control c : requestControls) {
        String oid = c.getOID();

        if (OID_LDAP_ASSERTION.equals(oid)) {
          LDAPAssertionRequestControl assertControl =
              getRequestControl(LDAPAssertionRequestControl.DECODER);

          SearchFilter assertionFilter;
          try {
            assertionFilter = assertControl.getSearchFilter();
          } catch (DirectoryException de) {
            if (debugEnabled()) {
              TRACER.debugCaught(DebugLogLevel.ERROR, de);
            }

            throw new DirectoryException(
                de.getResultCode(),
                ERR_SEARCH_CANNOT_PROCESS_ASSERTION_FILTER.get(de.getMessageObject()),
                de);
          }

          Entry entry;
          try {
            entry = DirectoryServer.getEntry(baseDN);
          } catch (DirectoryException de) {
            if (debugEnabled()) {
              TRACER.debugCaught(DebugLogLevel.ERROR, de);
            }

            throw new DirectoryException(
                de.getResultCode(),
                ERR_SEARCH_CANNOT_GET_ENTRY_FOR_ASSERTION.get(de.getMessageObject()));
          }

          if (entry == null) {
            throw new DirectoryException(
                ResultCode.NO_SUCH_OBJECT, ERR_SEARCH_NO_SUCH_ENTRY_FOR_ASSERTION.get());
          }

          // Check if the current user has permission to make
          // this determination.
          if (!AccessControlConfigManager.getInstance()
              .getAccessControlHandler()
              .isAllowed(this, entry, assertionFilter)) {
            throw new DirectoryException(
                ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
                ERR_CONTROL_INSUFFICIENT_ACCESS_RIGHTS.get(oid));
          }

          try {
            if (!assertionFilter.matchesEntry(entry)) {
              throw new DirectoryException(
                  ResultCode.ASSERTION_FAILED, ERR_SEARCH_ASSERTION_FAILED.get());
            }
          } catch (DirectoryException de) {
            if (de.getResultCode() == ResultCode.ASSERTION_FAILED) {
              throw de;
            }

            if (debugEnabled()) {
              TRACER.debugCaught(DebugLogLevel.ERROR, de);
            }

            throw new DirectoryException(
                de.getResultCode(),
                ERR_SEARCH_CANNOT_PROCESS_ASSERTION_FILTER.get(de.getMessageObject()),
                de);
          }
        } else if (OID_PROXIED_AUTH_V1.equals(oid)) {
          // Log usage of legacy proxy authz V1 control.
          addAdditionalLogItem(
              AdditionalLogItem.keyOnly(getClass(), "obsoleteProxiedAuthzV1Control"));

          // The requester must have the PROXIED_AUTH privilege in order to be
          // able to use this control.
          if (!clientConnection.hasPrivilege(Privilege.PROXIED_AUTH, this)) {
            throw new DirectoryException(
                ResultCode.AUTHORIZATION_DENIED, ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
          }

          ProxiedAuthV1Control proxyControl = getRequestControl(ProxiedAuthV1Control.DECODER);

          Entry authorizationEntry = proxyControl.getAuthorizationEntry();
          setAuthorizationEntry(authorizationEntry);
          setProxiedAuthorizationDN(getDN(authorizationEntry));
        } else if (OID_PROXIED_AUTH_V2.equals(oid)) {
          // The requester must have the PROXIED_AUTH privilege in order to be
          // able to use this control.
          if (!clientConnection.hasPrivilege(Privilege.PROXIED_AUTH, this)) {
            throw new DirectoryException(
                ResultCode.AUTHORIZATION_DENIED, ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
          }

          ProxiedAuthV2Control proxyControl = getRequestControl(ProxiedAuthV2Control.DECODER);

          Entry authorizationEntry = proxyControl.getAuthorizationEntry();
          setAuthorizationEntry(authorizationEntry);
          setProxiedAuthorizationDN(getDN(authorizationEntry));
        } else if (OID_PERSISTENT_SEARCH.equals(oid)) {
          final PersistentSearchControl ctrl = getRequestControl(PersistentSearchControl.DECODER);

          persistentSearch =
              new PersistentSearch(
                  this, ctrl.getChangeTypes(), ctrl.getChangesOnly(), ctrl.getReturnECs());
        } else if (OID_LDAP_SUBENTRIES.equals(oid)) {
          SubentriesControl subentriesControl = getRequestControl(SubentriesControl.DECODER);
          setReturnSubentriesOnly(subentriesControl.getVisibility());
        } else if (OID_LDUP_SUBENTRIES.equals(oid)) {
          // Support for legacy draft-ietf-ldup-subentry.
          addAdditionalLogItem(AdditionalLogItem.keyOnly(getClass(), "obsoleteSubentryControl"));

          setReturnSubentriesOnly(true);
        } else if (OID_MATCHED_VALUES.equals(oid)) {
          MatchedValuesControl matchedValuesControl =
              getRequestControl(MatchedValuesControl.DECODER);
          setMatchedValuesControl(matchedValuesControl);
        } else if (OID_ACCOUNT_USABLE_CONTROL.equals(oid)) {
          setIncludeUsableControl(true);
        } else if (OID_REAL_ATTRS_ONLY.equals(oid)) {
          setRealAttributesOnly(true);
        } else if (OID_VIRTUAL_ATTRS_ONLY.equals(oid)) {
          setVirtualAttributesOnly(true);
        } else if (OID_GET_EFFECTIVE_RIGHTS.equals(oid)
            && DirectoryServer.isSupportedControl(OID_GET_EFFECTIVE_RIGHTS)) {
          // Do nothing here and let AciHandler deal with it.
        }
        // NYI -- Add support for additional controls.

        else if (c.isCritical() && !backendSupportsControl(oid)) {
          throw new DirectoryException(
              ResultCode.UNAVAILABLE_CRITICAL_EXTENSION,
              ERR_SEARCH_UNSUPPORTED_CRITICAL_CONTROL.get(oid));
        }
      }
    }
  }