From e7f8533cf460901e7ec3503782d7b78baabd55a3 Mon Sep 17 00:00:00 2001
From: Fabio Pistolesi <fabio.pistolesi@forgerock.com>
Date: Fri, 13 Feb 2015 16:24:23 +0000
Subject: [PATCH] OPENDJ-1793 Convert PersistItBackendCfg references to PluggableBackendCfg

---
 opendj-server-legacy/src/main/java/org/opends/server/backends/persistit/PersistItStorage.java |  261 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 249 insertions(+), 12 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 7ab9291..77a78d0 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
@@ -27,17 +27,23 @@
 
 import static com.persistit.Transaction.CommitPolicy.*;
 import static java.util.Arrays.*;
+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.StaticUtils.*;
 
 import java.io.File;
 import java.io.FilenameFilter;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
+import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.forgerock.opendj.config.server.ConfigChangeResult;
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
+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.backends.pluggable.spi.Cursor;
@@ -49,6 +55,9 @@
 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.types.FilePermission;
 
 import com.persistit.Configuration;
 import com.persistit.Configuration.BufferPoolConfiguration;
@@ -65,7 +74,7 @@
 import com.persistit.exception.RollbackException;
 
 /** PersistIt database implementation of the {@link Storage} engine. */
-public final class PersistItStorage implements Storage
+public final class PersistItStorage implements Storage, ConfigurationChangeListener<PersistitBackendCfg>
 {
   private static final String VOLUME_NAME = "dj";
   /** The buffer / page size used by the PersistIt storage. */
@@ -504,6 +513,7 @@
         throw new IllegalStateException(e);
       }
     }
+    config.removePersistitChangeListener(this);
   }
 
   /** {@inheritDoc} */
@@ -537,6 +547,7 @@
       bufferPoolCfg.setFraction(cfg.getDBCachePercent() / 100.0f);
     }
     dbCfg.setCommitPolicy(cfg.isDBTxnNoSync() ? SOFT : GROUP);
+    cfg.addPersistitChangeListener(this);
   }
 
   private BufferPoolConfiguration getBufferPoolCfg()
@@ -553,8 +564,9 @@
 
   /** {@inheritDoc} */
   @Override
-  public void open()
+  public void open() throws Exception
   {
+    setupStorageFiles();
     try
     {
       db = new Persistit(dbCfg);
@@ -621,21 +633,15 @@
 
   /** {@inheritDoc} */
   @Override
-  public Importer startImport()
+  public Importer startImport() throws Exception
   {
     clearAndCreateDbDir(backendDirectory);
     open();
     return new ImporterImpl();
   }
 
-  /**
-   * Replace persistit reserved comma character with an underscore character.
-   *
-   * @param suffix
-   *          the suffix name to convert
-   * @return a new String suitable for use as a suffix name
-   */
-  public String toSuffixName(final String suffix)
+  /** {@inheritDoc} */
+  public String toSafeSuffixName(final String suffix)
   {
     return suffix.replaceAll("[,=]", "_");
   }
@@ -700,7 +706,7 @@
     };
   }
 
-  /*
+  /**
    * TODO: it would be nice to use the low-level key/value APIs. They seem quite
    * inefficient at the moment for simple byte arrays.
    */
@@ -735,4 +741,235 @@
     }
     return null;
   }
+
+  /** {@inheritDoc} */
+  @Override
+  public boolean isConfigurationChangeAcceptable(PersistitBackendCfg cfg, List<LocalizableMessage> unacceptableReasons)
+  {
+    boolean acceptable = true;
+
+    File parentDirectory = getFileForPath(config.getDBDirectory());
+    File backendDirectory = new File(parentDirectory, config.getBackendId());
+
+    //Make sure the directory either already exists or is able to create.
+    if (!backendDirectory.exists())
+    {
+      if(!backendDirectory.mkdirs())
+      {
+        unacceptableReasons.add(ERR_JEB_CREATE_FAIL.get(backendDirectory.getPath()));
+        acceptable = false;
+      }
+      else
+      {
+        backendDirectory.delete();
+      }
+    }
+    else if (!backendDirectory.isDirectory())
+    {
+      unacceptableReasons.add(ERR_JEB_DIRECTORY_INVALID.get(backendDirectory.getPath()));
+      acceptable = false;
+    }
+
+    try
+    {
+      FilePermission newBackendPermission =
+          FilePermission.decodeUNIXMode(cfg.getDBDirectoryPermissions());
+
+      //Make sure the mode will allow the server itself access to the database
+      if(!newBackendPermission.isOwnerWritable() ||
+          !newBackendPermission.isOwnerReadable() ||
+          !newBackendPermission.isOwnerExecutable())
+      {
+        LocalizableMessage message = ERR_CONFIG_BACKEND_INSANE_MODE.get(
+            cfg.getDBDirectoryPermissions());
+        unacceptableReasons.add(message);
+        acceptable = false;
+      }
+    }
+    catch(Exception e)
+    {
+      unacceptableReasons.add(ERR_CONFIG_BACKEND_MODE_INVALID.get(cfg.dn()));
+      acceptable = false;
+    }
+
+    return acceptable;
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public ConfigChangeResult applyConfigurationChange(PersistitBackendCfg cfg)
+  {
+    final ConfigChangeResult ccr = new ConfigChangeResult();
+
+    try
+    {
+      // Create the directory if it doesn't exist.
+      if(!cfg.getDBDirectory().equals(this.config.getDBDirectory()))
+      {
+        File parentDirectory = getFileForPath(cfg.getDBDirectory());
+        File backendDirectory =
+          new File(parentDirectory, cfg.getBackendId());
+
+        if (!backendDirectory.exists())
+        {
+          if (!backendDirectory.mkdirs())
+          {
+            ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
+            ccr.addMessage(ERR_JEB_CREATE_FAIL.get(backendDirectory.getPath()));
+            return ccr;
+          }
+        }
+        //Make sure the directory is valid.
+        else if (!backendDirectory.isDirectory())
+        {
+          ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
+          ccr.addMessage(ERR_JEB_DIRECTORY_INVALID.get(backendDirectory.getPath()));
+          return ccr;
+        }
+
+        ccr.setAdminActionRequired(true);
+        ccr.addMessage(NOTE_JEB_CONFIG_DB_DIR_REQUIRES_RESTART.get(this.config.getDBDirectory(),
+            cfg.getDBDirectory()));
+      }
+
+      if (!cfg.getDBDirectoryPermissions().equalsIgnoreCase(config.getDBDirectoryPermissions())
+          || !cfg.getDBDirectory().equals(this.config.getDBDirectory()))
+      {
+        FilePermission backendPermission;
+        try
+        {
+          backendPermission =
+              FilePermission.decodeUNIXMode(cfg.getDBDirectoryPermissions());
+        }
+        catch(Exception e)
+        {
+          ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
+          ccr.addMessage(ERR_CONFIG_BACKEND_MODE_INVALID.get(config.dn()));
+          return ccr;
+        }
+
+        // Make sure the mode will allow the server itself access to the database
+        if(!backendPermission.isOwnerWritable() ||
+            !backendPermission.isOwnerReadable() ||
+            !backendPermission.isOwnerExecutable())
+        {
+          ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
+          ccr.addMessage(ERR_CONFIG_BACKEND_INSANE_MODE.get(cfg.getDBDirectoryPermissions()));
+          return ccr;
+        }
+
+        // Get the backend database backendDirectory permissions and apply
+        if(FilePermission.canSetPermissions())
+        {
+          File parentDirectory = getFileForPath(config.getDBDirectory());
+          File backendDirectory = new File(parentDirectory, config.getBackendId());
+          try
+          {
+            if (!FilePermission.setPermissions(backendDirectory, backendPermission))
+            {
+              logger.warn(WARN_JEB_UNABLE_SET_PERMISSIONS, backendPermission, backendDirectory);
+            }
+          }
+          catch(Exception e)
+          {
+            // Log an warning that the permissions were not set.
+            logger.warn(WARN_JEB_SET_PERMISSIONS_FAILED, backendDirectory, e);
+          }
+        }
+      }
+
+      this.config = cfg;
+    }
+    catch (Exception e)
+    {
+      ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
+      ccr.addMessage(LocalizableMessage.raw(stackTraceToSingleLineString(e)));
+    }
+    return ccr;
+  }
+
+  /** {@inheritDoc} */
+  private void setupStorageFiles() throws Exception
+  {
+    // Create the directory if it doesn't exist.
+    if (!backendDirectory.exists())
+    {
+      if(!backendDirectory.mkdirs())
+      {
+        LocalizableMessage message =
+          ERR_JEB_CREATE_FAIL.get(backendDirectory.getPath());
+        throw new ConfigException(message);
+      }
+    }
+    //Make sure the directory is valid.
+    else if (!backendDirectory.isDirectory())
+    {
+      throw new ConfigException(ERR_JEB_DIRECTORY_INVALID.get(backendDirectory.getPath()));
+    }
+
+    FilePermission backendPermission;
+    try
+    {
+      backendPermission =
+          FilePermission.decodeUNIXMode(config.getDBDirectoryPermissions());
+    }
+    catch(Exception e)
+    {
+      throw new ConfigException(ERR_CONFIG_BACKEND_MODE_INVALID.get(config.dn()));
+    }
+
+    //Make sure the mode will allow the server itself access to
+    //the database
+    if(!backendPermission.isOwnerWritable() ||
+        !backendPermission.isOwnerReadable() ||
+        !backendPermission.isOwnerExecutable())
+    {
+      LocalizableMessage message = ERR_CONFIG_BACKEND_INSANE_MODE.get(
+          config.getDBDirectoryPermissions());
+      throw new ConfigException(message);
+    }
+
+    // Get the backend database backendDirectory permissions and apply
+    if(FilePermission.canSetPermissions())
+    {
+      try
+      {
+        if(!FilePermission.setPermissions(backendDirectory, backendPermission))
+        {
+          logger.warn(WARN_JEB_UNABLE_SET_PERMISSIONS, backendPermission, backendDirectory);
+        }
+      }
+      catch(Exception e)
+      {
+        // Log an warning that the permissions were not set.
+        logger.warn(WARN_JEB_SET_PERMISSIONS_FAILED, backendDirectory, e);
+      }
+    }
+  }
+
+  /** {@inheritDoc} */
+  public void removeStorageFiles() throws StorageRuntimeException
+  {
+    if (!backendDirectory.isDirectory())
+    {
+      LocalizableMessage msg = ERR_JEB_DIRECTORY_INVALID.get(backendDirectory.getPath());
+      throw new StorageRuntimeException(msg.toString());
+    }
+
+    try
+    {
+      File[] files = backendDirectory.listFiles();
+      for (File f : files)
+      {
+        f.delete();
+      }
+    }
+    catch (Exception e)
+    {
+      logger.traceException(e);
+      LocalizableMessage message = ERR_JEB_REMOVE_FAIL.get(e.getMessage());
+      throw new StorageRuntimeException(message.toString(), e);
+    }
+  }
 }
+

--
Gitblit v1.10.0