From 8b806159078ce1308b27e676c0e8a6340f05e6e0 Mon Sep 17 00:00:00 2001
From: Fabio Pistolesi <fabio.pistolesi@forgerock.com>
Date: Mon, 02 Mar 2015 10:59:04 +0000
Subject: [PATCH] OPENDJ-1826 CR-6180 BackendImpl current DiskSpaceMonitoring should be done entirely at the Storage layer

---
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/RootContainer.java               |   30 ++
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java                 |  238 +++++------------------
 opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/persistit/PersistitTestCase.java |   10 
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/Storage.java                 |   14 
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/StorageStatus.java           |  132 +++++++++++++
 opendj-server-legacy/src/main/java/org/opends/server/backends/persistit/PersistItStorage.java            |  104 +++++++++
 opendj-server-legacy/src/main/java/org/opends/server/backends/persistit/PitBackend.java                  |   28 --
 7 files changed, 324 insertions(+), 232 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/persistit/PersistItStorage.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/persistit/PersistItStorage.java
index 3a3a43b..e8be95f 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/persistit/PersistItStorage.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/persistit/PersistItStorage.java
@@ -30,13 +30,19 @@
 import static org.opends.messages.ConfigMessages.ERR_CONFIG_BACKEND_INSANE_MODE;
 import static org.opends.messages.ConfigMessages.ERR_CONFIG_BACKEND_MODE_INVALID;
 import static org.opends.messages.JebMessages.*;
+import static org.opends.server.util.ServerConstants.ALERT_DESCRIPTION_DISK_FULL;
+import static org.opends.server.util.ServerConstants.ALERT_DESCRIPTION_DISK_SPACE_LOW;
+import static org.opends.server.util.ServerConstants.ALERT_TYPE_DISK_FULL;
+import static org.opends.server.util.ServerConstants.ALERT_TYPE_DISK_SPACE_LOW;
 import static org.opends.server.util.StaticUtils.*;
 
 import java.io.File;
 import java.io.FilenameFilter;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
@@ -46,17 +52,22 @@
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.std.server.PersistitBackendCfg;
 import org.opends.server.admin.std.server.PluggableBackendCfg;
+import org.opends.server.api.AlertGenerator;
+import org.opends.server.api.DiskSpaceMonitorHandler;
 import org.opends.server.backends.pluggable.spi.Cursor;
 import org.opends.server.backends.pluggable.spi.Importer;
 import org.opends.server.backends.pluggable.spi.ReadOperation;
 import org.opends.server.backends.pluggable.spi.Storage;
 import org.opends.server.backends.pluggable.spi.StorageRuntimeException;
+import org.opends.server.backends.pluggable.spi.StorageStatus;
 import org.opends.server.backends.pluggable.spi.TreeName;
 import org.opends.server.backends.pluggable.spi.UpdateFunction;
 import org.opends.server.backends.pluggable.spi.WriteOperation;
 import org.opends.server.backends.pluggable.spi.WriteableStorage;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
+import org.opends.server.extensions.DiskSpaceMonitor;
+import org.opends.server.types.DN;
 import org.opends.server.types.FilePermission;
 
 import com.persistit.Configuration;
@@ -74,7 +85,8 @@
 import com.persistit.exception.RollbackException;
 
 /** PersistIt database implementation of the {@link Storage} engine. */
-public final class PersistItStorage implements Storage, ConfigurationChangeListener<PersistitBackendCfg>
+public final class PersistItStorage implements Storage, ConfigurationChangeListener<PersistitBackendCfg>,
+  DiskSpaceMonitorHandler, AlertGenerator
 {
   private static final String VOLUME_NAME = "dj";
   /** The buffer / page size used by the PersistIt storage. */
@@ -501,6 +513,7 @@
   private Volume volume;
   private Configuration dbCfg;
   private PersistitBackendCfg config;
+  private DiskSpaceMonitor diskMonitor;
 
   /** {@inheritDoc} */
   @Override
@@ -519,6 +532,8 @@
       }
     }
     config.removePersistitChangeListener(this);
+    DirectoryServer.deregisterMonitorProvider(diskMonitor);
+    DirectoryServer.deregisterAlertGenerator(this);
   }
 
   /** {@inheritDoc} */
@@ -562,13 +577,6 @@
 
   /** {@inheritDoc} */
   @Override
-  public boolean isValid()
-  {
-    return !db.isFatal();
-  }
-
-  /** {@inheritDoc} */
-  @Override
   public void open() throws Exception
   {
     setupStorageFiles();
@@ -588,6 +596,11 @@
     {
       throw new StorageRuntimeException(e);
     }
+    // Register as disk space monitor handler
+    diskMonitor = newDiskMonitor(config);
+    DirectoryServer.registerMonitorProvider(diskMonitor);
+    //Register as an AlertGenerator.
+    DirectoryServer.registerAlertGenerator(this);
   }
 
   /** {@inheritDoc} */
@@ -900,6 +913,8 @@
 
         setDBDirPermissions(cfg, newBackendDirectory);
       }
+      diskMonitor.setFullThreshold(cfg.getDiskFullThreshold());
+      diskMonitor.setLowThreshold(cfg.getDiskLowThreshold());
 
       config = cfg;
     }
@@ -957,5 +972,78 @@
       throw new StorageRuntimeException(message.toString(), e);
     }
   }
+
+  @Override
+  public StorageStatus getStorageStatus()
+  {
+    if (diskMonitor.isFullThresholdReached())
+    {
+      return StorageStatus.unusable(WARN_JEB_OUT_OF_DISK_SPACE.get());
+    }
+    if (diskMonitor.isLowThresholdReached())
+    {
+      return StorageStatus.lockedDown(WARN_JEB_OUT_OF_DISK_SPACE.get());
+    }
+    return StorageStatus.working();
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public void diskFullThresholdReached(DiskSpaceMonitor monitor) {
+    LocalizableMessage msg = ERR_JEB_DISK_FULL_THRESHOLD_REACHED.get(
+        monitor.getDirectory().getPath(), config.getBackendId(), monitor.getFreeSpace(),
+        Math.max(monitor.getLowThreshold(), monitor.getFullThreshold()));
+    DirectoryServer.sendAlertNotification(this, ALERT_TYPE_DISK_FULL, msg);
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public void diskLowThresholdReached(DiskSpaceMonitor monitor) {
+    LocalizableMessage msg = ERR_JEB_DISK_LOW_THRESHOLD_REACHED.get(
+        monitor.getDirectory().getPath(), config.getBackendId(), monitor.getFreeSpace(),
+        Math.max(monitor.getLowThreshold(), monitor.getFullThreshold()));
+    DirectoryServer.sendAlertNotification(this, ALERT_TYPE_DISK_SPACE_LOW, msg);
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public void diskSpaceRestored(DiskSpaceMonitor monitor) {
+    logger.error(NOTE_JEB_DISK_SPACE_RESTORED, monitor.getFreeSpace(),
+        monitor.getDirectory().getPath(), config.getBackendId(),
+        Math.max(monitor.getLowThreshold(), monitor.getFullThreshold()));
+  }
+
+  private DiskSpaceMonitor newDiskMonitor(PersistitBackendCfg config) throws Exception
+  {
+    File parentDirectory = getFileForPath(config.getDBDirectory());
+    File backendDirectory = new File(parentDirectory, config.getBackendId());
+    DiskSpaceMonitor dm = new DiskSpaceMonitor(config.getBackendId() + " backend",
+        backendDirectory, config.getDiskLowThreshold(), config.getDiskFullThreshold(),
+        5, TimeUnit.SECONDS, this);
+    dm.initializeMonitorProvider(null);
+    return dm;
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public DN getComponentEntryDN() {
+    return config.dn();
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public String getClassName() {
+    return PersistItStorage.class.getName();
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public Map<String, String> getAlerts()
+  {
+    Map<String, String> alerts = new LinkedHashMap<String, String>();
+    alerts.put(ALERT_TYPE_DISK_SPACE_LOW, ALERT_DESCRIPTION_DISK_SPACE_LOW);
+    alerts.put(ALERT_TYPE_DISK_FULL, ALERT_DESCRIPTION_DISK_FULL);
+    return alerts;
+  }
 }
 
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/persistit/PitBackend.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/persistit/PitBackend.java
index 9c84a9c..128456c 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/persistit/PitBackend.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/persistit/PitBackend.java
@@ -29,15 +29,11 @@
 import static org.opends.server.util.StaticUtils.getFileForPath;
 
 import java.io.File;
-import java.util.concurrent.TimeUnit;
 
-import org.forgerock.opendj.config.server.ConfigException;
 import org.opends.server.admin.std.server.PersistitBackendCfg;
 import org.opends.server.admin.std.server.PluggableBackendCfg;
 import org.opends.server.backends.pluggable.BackendImpl;
 import org.opends.server.backends.pluggable.spi.Storage;
-import org.opends.server.extensions.DiskSpaceMonitor;
-import org.opends.server.types.InitializationException;
 
 /**
  * Class defined in the configuration for this backend type.
@@ -52,30 +48,6 @@
   }
 
   /** {@inheritDoc} */
-  @Override
-  public DiskSpaceMonitor newDiskMonitor(PluggableBackendCfg cfg) throws ConfigException, InitializationException
-  {
-    PersistitBackendCfg config = (PersistitBackendCfg) cfg;
-    File parentDirectory = getFileForPath(config.getDBDirectory());
-    File backendDirectory =
-        new File(parentDirectory, config.getBackendId());
-    DiskSpaceMonitor dm = new DiskSpaceMonitor(getBackendID() + " backend",
-        backendDirectory, config.getDiskLowThreshold(), config.getDiskFullThreshold(),
-        5, TimeUnit.SECONDS, this);
-    dm.initializeMonitorProvider(null);
-    return dm;
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public void updateDiskMonitor(DiskSpaceMonitor dm, PluggableBackendCfg newConfig)
-  {
-    PersistitBackendCfg newCfg = (PersistitBackendCfg) newConfig;
-    dm.setFullThreshold(newCfg.getDiskFullThreshold());
-    dm.setLowThreshold(newCfg.getDiskLowThreshold());
-  }
-
-  /** {@inheritDoc} */
   protected File getBackupDirectory(PluggableBackendCfg cfg)
   {
     PersistitBackendCfg config = (PersistitBackendCfg) cfg;
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java
index d2bc610..5dfb6f4 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/BackendImpl.java
@@ -49,9 +49,7 @@
 import org.opends.server.admin.std.meta.BackendIndexCfgDefn;
 import org.opends.server.admin.std.server.PersistitBackendCfg;
 import org.opends.server.admin.std.server.PluggableBackendCfg;
-import org.opends.server.api.AlertGenerator;
 import org.opends.server.api.Backend;
-import org.opends.server.api.DiskSpaceMonitorHandler;
 import org.opends.server.api.MonitorProvider;
 import org.opends.server.backends.RebuildConfig;
 import org.opends.server.backends.VerifyConfig;
@@ -60,7 +58,6 @@
 import org.opends.server.backends.pluggable.spi.WriteOperation;
 import org.opends.server.backends.pluggable.spi.WriteableStorage;
 import org.opends.server.core.*;
-import org.opends.server.extensions.DiskSpaceMonitor;
 import org.opends.server.types.*;
 
 /**
@@ -68,8 +65,7 @@
  * locally in a Berkeley DB JE database.
  */
 public abstract class BackendImpl extends Backend<PluggableBackendCfg> implements
-    ConfigurationChangeListener<PluggableBackendCfg>, AlertGenerator,
-    DiskSpaceMonitorHandler
+    ConfigurationChangeListener<PluggableBackendCfg>
 {
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
@@ -85,9 +81,6 @@
   private DN[] baseDNs;
 
   private MonitorProvider<?> rootContainerMonitor;
-  /** Disk space monitoring if the storage supports it. */
-  private DiskSpaceMonitor diskMonitor;
-
   /** The controls supported by this backend. */
   private static final Set<String> supportedControls = new HashSet<String>(Arrays.asList(
       OID_SUBTREE_DELETE_CONTROL,
@@ -96,10 +89,24 @@
       OID_SERVER_SIDE_SORT_REQUEST_CONTROL,
       OID_VLV_REQUEST_CONTROL));
 
-  /** Begin a Backend API method that accesses the database. */
-  private void accessBegin()
+  /**
+   * Begin a Backend API method that accesses the database and returns the <code>EntryContainer</code> for
+   * <code>entryDN</code>.
+   * @param operation requesting the storage
+   * @param entryDN the target DN for the operation
+   * @return <code>EntryContainer</code> where <code>entryDN</code> resides
+   */
+  private EntryContainer accessBegin(Operation operation, DN entryDN) throws DirectoryException
   {
+    checkRootContainerInitialized();
+    rootContainer.checkForEnoughResources(operation);
+    EntryContainer ec = rootContainer.getEntryContainer(entryDN);
+    if (ec == null)
+    {
+      throw new DirectoryException(ResultCode.UNDEFINED, ERR_BACKEND_ENTRY_DOESNT_EXIST.get(entryDN, getBackendID()));
+    }
     threadTotalCount.getAndIncrement();
+    return ec;
   }
 
   /** End a Backend API method that accesses the database. */
@@ -181,39 +188,10 @@
     rootContainerMonitor = rootContainer.getMonitorProvider();
     DirectoryServer.registerMonitorProvider(rootContainerMonitor);
 
-    // Register as disk space monitor handler
-    diskMonitor = newDiskMonitor(cfg);
-    if (diskMonitor != null)
-    {
-      DirectoryServer.registerMonitorProvider(diskMonitor);
-    }
-    //Register as an AlertGenerator.
-    DirectoryServer.registerAlertGenerator(this);
     // Register this backend as a change listener.
     cfg.addPluggableChangeListener(this);
   }
 
-  /**
-   * Let the storage create a new disk monitor if supported.
-   *
-   * @param cfg this storage current configuration
-   * @return a new disk monitor if supported or null
-   *
-   * @throws ConfigException if configuration is incorrect
-   * @throws InitializationException when disk monitor cannot be initialized
-   */
-  protected abstract DiskSpaceMonitor newDiskMonitor(PluggableBackendCfg cfg) throws
-    ConfigException, InitializationException;
-
-  /**
-   * Updates the disk monitor when configuration changes.
-   *
-   * @param dm the disk monitor to update
-   * @param newCfg the new configuration
-   */
-  protected abstract void updateDiskMonitor(DiskSpaceMonitor dm, PluggableBackendCfg newCfg);
-
-
   /** {@inheritDoc} */
   @Override
   public void finalizeBackend()
@@ -235,7 +213,6 @@
     }
 
     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
@@ -254,8 +231,6 @@
       logger.error(ERR_JEB_DATABASE_EXCEPTION, e.getMessage());
     }
 
-    DirectoryServer.deregisterAlertGenerator(this);
-
     // Make sure the thread counts are zero for next initialization.
     threadTotalCount.set(0);
 
@@ -364,8 +339,7 @@
 
   /** {@inheritDoc} */
   @Override
-  public ConditionResult hasSubordinates(DN entryDN)
-         throws DirectoryException
+  public ConditionResult hasSubordinates(DN entryDN) throws DirectoryException
   {
     long ret = numSubordinates(entryDN, false);
     if(ret < 0)
@@ -379,17 +353,26 @@
 
   /** {@inheritDoc} */
   @Override
-  public long numSubordinates(DN entryDN, boolean subtree)
-      throws DirectoryException
+  public long numSubordinates(DN entryDN, boolean subtree) throws DirectoryException
   {
-    checkRootContainerInitialized();
-    EntryContainer ec = rootContainer.getEntryContainer(entryDN);
-    if(ec == null)
+    EntryContainer ec;
+
+    /*
+     * Only place where we need special handling. Should return -1 instead of an
+     * error if the EntryContainer is null...
+     */
+    try {
+      ec = accessBegin(null, entryDN);
+    }
+    catch (DirectoryException de)
     {
-      return -1;
+      if (de.getResultCode() == ResultCode.UNDEFINED)
+      {
+        return -1;
+      }
+      throw de;
     }
 
-    accessBegin();
     ec.sharedLock.lock();
     try
     {
@@ -419,10 +402,8 @@
   @Override
   public Entry getEntry(DN entryDN) throws DirectoryException
   {
-    accessBegin();
+    EntryContainer ec = accessBegin(null, entryDN);
 
-    checkRootContainerInitialized();
-    EntryContainer ec = rootContainer.getEntryContainer(entryDN);
     ec.sharedLock.lock();
     Entry entry;
     try
@@ -447,14 +428,10 @@
 
   /** {@inheritDoc} */
   @Override
-  public void addEntry(Entry entry, AddOperation addOperation)
-      throws DirectoryException, CanceledOperationException
+  public void addEntry(Entry entry, AddOperation addOperation) throws DirectoryException, CanceledOperationException
   {
-    checkDiskSpace(addOperation);
-    accessBegin();
+    EntryContainer ec = accessBegin(addOperation, entry.getName());
 
-    checkRootContainerInitialized();
-    EntryContainer ec = rootContainer.getEntryContainer(entry.getName());
     ec.sharedLock.lock();
     try
     {
@@ -479,11 +456,8 @@
   public void deleteEntry(DN entryDN, DeleteOperation deleteOperation)
       throws DirectoryException, CanceledOperationException
   {
-    checkDiskSpace(deleteOperation);
-    accessBegin();
+    EntryContainer ec = accessBegin(deleteOperation, entryDN);
 
-    checkRootContainerInitialized();
-    EntryContainer ec = rootContainer.getEntryContainer(entryDN);
     ec.sharedLock.lock();
     try
     {
@@ -505,15 +479,11 @@
 
   /** {@inheritDoc} */
   @Override
-  public void replaceEntry(Entry oldEntry, Entry newEntry,
-      ModifyOperation modifyOperation) throws DirectoryException,
-      CanceledOperationException
+  public void replaceEntry(Entry oldEntry, Entry newEntry, ModifyOperation modifyOperation)
+      throws DirectoryException, CanceledOperationException
   {
-    checkDiskSpace(modifyOperation);
-    accessBegin();
+    EntryContainer ec = accessBegin(modifyOperation, newEntry.getName());
 
-    checkRootContainerInitialized();
-    EntryContainer ec = rootContainer.getEntryContainer(newEntry.getName());
     ec.sharedLock.lock();
 
     try
@@ -536,23 +506,18 @@
 
   /** {@inheritDoc} */
   @Override
-  public void renameEntry(DN currentDN, Entry entry,
-                          ModifyDNOperation modifyDNOperation)
+  public void renameEntry(DN currentDN, Entry entry, ModifyDNOperation modifyDNOperation)
       throws DirectoryException, CanceledOperationException
   {
-    checkDiskSpace(modifyDNOperation);
-    accessBegin();
-
-    checkRootContainerInitialized();
-    EntryContainer currentContainer = rootContainer.getEntryContainer(currentDN);
+    EntryContainer currentContainer = accessBegin(modifyDNOperation, currentDN);
     EntryContainer container = rootContainer.getEntryContainer(entry.getName());
 
     if (currentContainer != container)
     {
+      accessEnd();
       // FIXME: No reason why we cannot implement a move between containers
       // since the containers share the same database environment.
-      LocalizableMessage msg = WARN_JEB_FUNCTION_NOT_SUPPORTED.get();
-      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, msg);
+      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, WARN_JEB_FUNCTION_NOT_SUPPORTED.get());
     }
 
     currentContainer.sharedLock.lock();
@@ -576,13 +541,10 @@
 
   /** {@inheritDoc} */
   @Override
-  public void search(SearchOperation searchOperation)
-      throws DirectoryException, CanceledOperationException
+  public void search(SearchOperation searchOperation) throws DirectoryException, CanceledOperationException
   {
-    accessBegin();
+    EntryContainer ec = accessBegin(searchOperation, searchOperation.getBaseDN());
 
-    checkRootContainerInitialized();
-    EntryContainer ec = rootContainer.getEntryContainer(searchOperation.getBaseDN());
     ec.sharedLock.lock();
 
     try
@@ -876,11 +838,6 @@
 
             baseDNs = newBaseDNsArray;
 
-            if (diskMonitor != null)
-            {
-              updateDiskMonitor(diskMonitor, newCfg);
-            }
-
             // Put the new configuration in place.
             cfg = newCfg;
           }
@@ -975,62 +932,18 @@
    */
   private DirectoryException createDirectoryException(StorageRuntimeException e)
   {
-    if (true) // FIXME JNR
+    Throwable cause = e.getCause();
+    if (cause instanceof OpenDsException)
     {
-      Throwable cause = e.getCause();
-      if (cause instanceof OpenDsException)
-      {
-        return new DirectoryException(
-            DirectoryServer.getServerErrorResultCode(), (OpenDsException) cause);
-      }
-      else
-      {
-        return new DirectoryException(
-            DirectoryServer.getServerErrorResultCode(),
-            LocalizableMessage.raw(e.getMessage()), e);
-      }
+      return new DirectoryException(
+          DirectoryServer.getServerErrorResultCode(), (OpenDsException) cause);
     }
-    if (/*e instanceof EnvironmentFailureException && */ !rootContainer.isValid()) {
-      LocalizableMessage message = NOTE_BACKEND_ENVIRONMENT_UNUSABLE.get(getBackendID());
-      logger.info(message);
-      DirectoryServer.sendAlertNotification(DirectoryServer.getInstance(),
-              ALERT_TYPE_BACKEND_ENVIRONMENT_UNUSABLE, message);
+    else
+    {
+      return new DirectoryException(
+          DirectoryServer.getServerErrorResultCode(),
+          LocalizableMessage.raw(e.getMessage()), e);
     }
-
-    String jeMessage = e.getMessage();
-    if (jeMessage == null) {
-      jeMessage = stackTraceToSingleLineString(e);
-    }
-    LocalizableMessage message = ERR_JEB_DATABASE_EXCEPTION.get(jeMessage);
-    return new DirectoryException(
-        DirectoryServer.getServerErrorResultCode(), message, e);
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public String getClassName() {
-    return BackendImpl.class.getName();
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public Map<String, String> getAlerts()
-  {
-    Map<String, String> alerts = new LinkedHashMap<String, String>();
-
-    alerts.put(ALERT_TYPE_BACKEND_ENVIRONMENT_UNUSABLE,
-            ALERT_DESCRIPTION_BACKEND_ENVIRONMENT_UNUSABLE);
-    alerts.put(ALERT_TYPE_DISK_SPACE_LOW,
-            ALERT_DESCRIPTION_DISK_SPACE_LOW);
-    alerts.put(ALERT_TYPE_DISK_FULL,
-            ALERT_DESCRIPTION_DISK_FULL);
-    return alerts;
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public DN getComponentEntryDN() {
-    return cfg.dn();
   }
 
   private RootContainer initializeRootContainer()
@@ -1056,43 +969,4 @@
     EntryCachePreloader preloader = new EntryCachePreloader(this);
     preloader.preload();
   }
-
-  /** {@inheritDoc} */
-  @Override
-  public void diskLowThresholdReached(DiskSpaceMonitor monitor) {
-    LocalizableMessage msg = ERR_JEB_DISK_LOW_THRESHOLD_REACHED.get(
-        monitor.getDirectory().getPath(), cfg.getBackendId(), monitor.getFreeSpace(),
-        Math.max(monitor.getLowThreshold(), monitor.getFullThreshold()));
-    DirectoryServer.sendAlertNotification(this, ALERT_TYPE_DISK_SPACE_LOW, msg);
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public void diskFullThresholdReached(DiskSpaceMonitor monitor) {
-    LocalizableMessage msg = ERR_JEB_DISK_FULL_THRESHOLD_REACHED.get(
-        monitor.getDirectory().getPath(), cfg.getBackendId(), monitor.getFreeSpace(),
-        Math.max(monitor.getLowThreshold(), monitor.getFullThreshold()));
-    DirectoryServer.sendAlertNotification(this, ALERT_TYPE_DISK_FULL, msg);
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public void diskSpaceRestored(DiskSpaceMonitor monitor) {
-    logger.error(NOTE_JEB_DISK_SPACE_RESTORED, monitor.getFreeSpace(),
-        monitor.getDirectory().getPath(), cfg.getBackendId(),
-        Math.max(monitor.getLowThreshold(), monitor.getFullThreshold()));
-  }
-
-  private void checkDiskSpace(Operation operation) throws DirectoryException
-  {
-    if(diskMonitor.isFullThresholdReached() ||
-        (diskMonitor.isLowThresholdReached()
-            && operation != null
-            && !operation.getClientConnection().hasPrivilege(
-                Privilege.BYPASS_LOCKDOWN, operation)))
-    {
-      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
-          WARN_JEB_OUT_OF_DISK_SPACE.get());
-    }
-  }
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/RootContainer.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/RootContainer.java
index 7bee231..716ff46 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/RootContainer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/RootContainer.java
@@ -53,6 +53,7 @@
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.forgerock.opendj.config.server.ConfigChangeResult;
 import org.forgerock.opendj.config.server.ConfigException;
+import org.forgerock.opendj.ldap.ResultCode;
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.std.server.PluggableBackendCfg;
 import org.opends.server.api.CompressedSchema;
@@ -60,9 +61,11 @@
 import org.opends.server.backends.pluggable.spi.ReadableStorage;
 import org.opends.server.backends.pluggable.spi.Storage;
 import org.opends.server.backends.pluggable.spi.StorageRuntimeException;
+import org.opends.server.backends.pluggable.spi.StorageStatus;
 import org.opends.server.backends.pluggable.spi.WriteOperation;
 import org.opends.server.backends.pluggable.spi.WriteableStorage;
 import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.SearchOperation;
 import org.opends.server.types.DN;
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.Entry;
@@ -70,6 +73,8 @@
 import org.opends.server.types.LDIFImportConfig;
 import org.opends.server.types.LDIFImportResult;
 import org.opends.server.types.OpenDsException;
+import org.opends.server.types.Operation;
+import org.opends.server.types.Privilege;
 import org.opends.server.util.LDIFException;
 import org.opends.server.util.LDIFReader;
 import org.opends.server.util.RuntimeInformation;
@@ -690,12 +695,27 @@
   }
 
   /**
-   * Returns whether this container JE database environment is open, valid and
-   * can be used.
+   * Checks the storage has enough resources for an operation.
    *
-   * @return {@code true} if valid, or {@code false} otherwise.
+   * @param operation the current operation
+   * @throws DirectoryException if resources are in short supply
    */
-  public boolean isValid() {
-    return storage.isValid();
+  public void checkForEnoughResources(Operation operation) throws DirectoryException
+  {
+    StorageStatus status = storage.getStorageStatus();
+    if (status.isUnusable()
+        || (status.isLockedDown() && hasBypassLockdownPrivileges(operation)))
+    {
+      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, status.getReason());
+    }
+  }
+
+  private boolean hasBypassLockdownPrivileges(Operation operation)
+  {
+    return operation != null
+          // Read operations are always allowed in lock down mode
+          && !(operation instanceof SearchOperation)
+          && !operation.getClientConnection().hasPrivilege(
+              Privilege.BYPASS_LOCKDOWN, operation);
   }
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/Storage.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/Storage.java
index 004b604..084fe89 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/Storage.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/Storage.java
@@ -100,13 +100,6 @@
   void closeTree(TreeName treeName);
 
   /**
-   * Returns whether the storage engine is in a valid state, i.e. whether it can be used for processing.
-   *
-   * @return {@code true} if the storage engine is in a valid state, {@code false} otherwise
-   */
-  boolean isValid();
-
-  /**
    * Returns a filename filter which selects the files to be included in a backup.
    * @return a filename filter which selects the files to be included in a backup
    */
@@ -122,4 +115,11 @@
    * @throws StorageRuntimeException if removal fails
    */
   void removeStorageFiles() throws StorageRuntimeException;
+
+  /**
+   * Returns the current status of the storage.
+   *
+   * @return the current status of the storage
+   */
+  StorageStatus getStorageStatus();
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/StorageStatus.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/StorageStatus.java
new file mode 100644
index 0000000..dd55dd6
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/spi/StorageStatus.java
@@ -0,0 +1,132 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2015 ForgeRock AS
+ */
+
+package org.opends.server.backends.pluggable.spi;
+
+import org.forgerock.i18n.LocalizableMessage;
+
+/**
+ * Represents the current status of a storage with respect to its resources.
+ */
+public final class StorageStatus
+{
+  /** Internal States. */
+  private enum Code
+  {
+    /** Storage is working normally. */
+    WORKING,
+    /** Storage resources start getting scarce. */
+    LOCKED_DOWN,
+    /** Storage has no resources to execute operations. */
+    UNUSABLE
+  };
+
+  /** Hopefully resources are always in this state. */
+  private static final StorageStatus WORKING = new StorageStatus(Code.WORKING, null);
+
+  /** Current status. */
+  private final Code code;
+  /** Current warning/error message. */
+  private final LocalizableMessage reason;
+
+  /**
+   * Returns normal state.
+   *
+   * @return normal state
+   */
+  public static StorageStatus working()
+  {
+    return WORKING;
+  }
+
+  /**
+   * Returns state for resources getting scarce.
+   *
+   * @param reason the message to forward
+   * @return state for resources getting scarce
+   */
+  public static StorageStatus lockedDown(LocalizableMessage reason)
+  {
+    return new StorageStatus(Code.LOCKED_DOWN, reason);
+  }
+
+  /**
+   * Returns state for no more resources.
+   *
+   * @param reason the message to forward
+   * @return state for no more resources
+   */
+  public static StorageStatus unusable(LocalizableMessage reason)
+  {
+    return new StorageStatus(Code.UNUSABLE, reason);
+  }
+
+  private StorageStatus(Code code, LocalizableMessage reason)
+  {
+    this.code = code;
+    this.reason = reason;
+  }
+
+  /**
+   * Returns true if resources are getting scarce.
+   *
+   * @return true if resources are getting scarce
+   */
+  public boolean isLockedDown()
+  {
+    return code == Code.LOCKED_DOWN;
+  }
+
+  /**
+   * Returns true if state is normal.
+   *
+   * @return true if state is normal
+   */
+  public boolean isWorking()
+  {
+    return code == Code.WORKING;
+  }
+
+  /**
+   * Returns true if no more resources are available.
+   *
+   * @return true if no more resources are available
+   */
+  public boolean isUnusable()
+  {
+    return code == Code.UNUSABLE;
+  }
+
+  /**
+   * Returns the error message for non working states.
+   *
+   * @return the error message for non working states
+   */
+  public LocalizableMessage getReason()
+  {
+    return reason;
+  }
+}
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/persistit/PersistitTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/persistit/PersistitTestCase.java
index e087d5c..8f5967a 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/persistit/PersistitTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/persistit/PersistitTestCase.java
@@ -28,7 +28,6 @@
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertTrue;
 
 import org.forgerock.opendj.config.server.ConfigException;
 import org.opends.server.TestCaseUtils;
@@ -46,10 +45,17 @@
  */
 public class PersistitTestCase extends PluggableBackendImplTestCase
 {
+  /**
+   * Tests the storage API for resource checking.
+   * The tested method has no return value, but an exception, while not systematic, may be thrown,
+   * in which case the test must fail.
+   *
+   * @throws Exception if resources are low.
+   */
   @Test
   public void testPersistitCfg() throws Exception
   {
-    assertTrue(backend.getRootContainer().isValid());
+    backend.getRootContainer().checkForEnoughResources(null);
   }
 
   @Override

--
Gitblit v1.10.0