From 742e19dca031dc15aa54ea9b0e64bf485478627d Mon Sep 17 00:00:00 2001
From: kenneth_suter <kenneth_suter@localhost>
Date: Tue, 16 Oct 2007 20:19:45 +0000
Subject: [PATCH] Issue 2368: tasks should be interruptable.  The four schedulable task (import-ldif, export-ldif, backup, and restore) can now be interrupted for purposes of cancellation.  The manage-tasks utility now allows the user to cancel any one of these tasks if they are currently running.  If interrupted while executing, the tasks try to break out of their work loop as soon as possible and return a 'stopped by administrator' status.  Both the backup and export-ldif tasks perform some cleanup (removing the abandoned backup or exported LDIF file) if they are cancelled.

---
 opendj-sdk/opends/src/server/org/opends/server/backends/jeb/BackupManager.java            |   25 ++-
 opendj-sdk/opends/src/server/org/opends/server/types/OperationConfig.java                 |   66 +++++++++
 opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ImportJob.java                |   11 +
 opendj-sdk/opends/src/server/org/opends/server/tasks/ImportTask.java                      |   30 ++++
 opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskState.java               |   20 ++
 opendj-sdk/opends/src/server/org/opends/server/tasks/ExportTask.java                      |   45 ++++++
 opendj-sdk/opends/src/server/org/opends/server/types/LDIFExportConfig.java                |    2 
 opendj-sdk/opends/src/server/org/opends/server/tasks/RestoreTask.java                     |   32 ++++
 opendj-sdk/opends/src/server/org/opends/server/replication/server/ReplicationBackend.java |   18 ++
 opendj-sdk/opends/src/server/org/opends/server/types/BackupConfig.java                    |    2 
 opendj-sdk/opends/src/server/org/opends/server/types/RestoreConfig.java                   |    2 
 opendj-sdk/opends/src/server/org/opends/server/backends/SchemaBackend.java                |    7 
 opendj-sdk/opends/src/messages/messages/tools.properties                                  |    2 
 opendj-sdk/opends/src/server/org/opends/server/tasks/BackupTask.java                      |   40 +++++
 opendj-sdk/opends/src/server/org/opends/server/backends/task/Task.java                    |   71 ++++++++++
 opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java          |   12 +
 opendj-sdk/opends/src/messages/messages/task.properties                                   |    3 
 opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ExportJob.java                |   10 +
 opendj-sdk/opends/src/server/org/opends/server/types/LDIFImportConfig.java                |    2 
 19 files changed, 373 insertions(+), 27 deletions(-)

diff --git a/opendj-sdk/opends/src/messages/messages/task.properties b/opendj-sdk/opends/src/messages/messages/task.properties
index a751b3a..a9c05b4 100644
--- a/opendj-sdk/opends/src/messages/messages/task.properties
+++ b/opendj-sdk/opends/src/messages/messages/task.properties
@@ -185,4 +185,5 @@
 INFO_IMPORT_ARG_CLEAR_BACKEND_98=Clear Backend
 INFO_FAILED_DEPENDENCY_ACTION_PROCESS_99=Process
 INFO_FAILED_DEPENDENCY_ACTION_CANCEL_100=Cancel
-INFO_FAILED_DEPENDENCY_ACTION_DISABLE_101=Disable
\ No newline at end of file
+INFO_FAILED_DEPENDENCY_ACTION_DISABLE_101=Disable
+INFO_TASK_STOPPED_BY_ADMIN_102=Task was stopped by an administrator:  %s
\ No newline at end of file
diff --git a/opendj-sdk/opends/src/messages/messages/tools.properties b/opendj-sdk/opends/src/messages/messages/tools.properties
index e3e539a..c06a7d3 100644
--- a/opendj-sdk/opends/src/messages/messages/tools.properties
+++ b/opendj-sdk/opends/src/messages/messages/tools.properties
@@ -2188,4 +2188,4 @@
   option is to be used in conjunction with one or more dependencies
 SEVERE_ERR_TASKINFO_TASK_NOT_CANCELABLE_TASK_1477=Error:  task %s is not in a \
   cancelable state
-
+NOTICE_BACKUPDB_CANCELLED_1478=The backup process was cancelled
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/SchemaBackend.java b/opendj-sdk/opends/src/server/org/opends/server/backends/SchemaBackend.java
index bd9a312..91a19a0 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/SchemaBackend.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/SchemaBackend.java
@@ -4277,6 +4277,11 @@
     byte[] buffer = new byte[8192];
     for (File schemaFile : schemaFiles)
     {
+      if (backupConfig.isCancelled())
+      {
+        break;
+      }
+
       if (! schemaFile.isFile())
       {
         // If there are any non-file items in the directory (e.g., one or more
@@ -4310,7 +4315,7 @@
         while (true)
         {
           int bytesRead = inputStream.read(buffer);
-          if (bytesRead < 0)
+          if (bytesRead < 0 || backupConfig.isCancelled())
           {
             break;
           }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/BackupManager.java b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/BackupManager.java
index ccd5b5c..6b88b97 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/BackupManager.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/BackupManager.java
@@ -476,7 +476,8 @@
       if (latestFileName != null)
       {
         ArrayList<String> unchangedList = new ArrayList<String>();
-        while (indexCurrent < logFiles.length)
+        while (indexCurrent < logFiles.length &&
+                !backupConfig.isCancelled())
         {
           File logFile = logFiles[indexCurrent];
           String logFileName = logFile.getName();
@@ -528,13 +529,15 @@
       {
         boolean deletedFiles = false;
 
-        while (indexCurrent < logFiles.length)
+        while (indexCurrent < logFiles.length &&
+                !backupConfig.isCancelled())
         {
           File logFile = logFiles[indexCurrent];
 
           try
           {
-            latestFileSize = archiveFile(zipStream, mac, digest, logFile);
+            latestFileSize = archiveFile(zipStream, mac, digest,
+                                         logFile, backupConfig);
             latestFileName = logFile.getName();
           }
           catch (FileNotFoundException e)
@@ -695,6 +698,13 @@
       throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                    message, e);
     }
+
+    // Remove the backup if this operation was cancelled since the
+    // backup may be incomplete
+    if (backupConfig.isCancelled())
+    {
+      removeBackup(backupDir, backupID);
+    }
   }
 
 
@@ -991,7 +1001,7 @@
 
     // Iterate through the entries in the zip file.
     ZipEntry zipEntry = zipStream.getNextEntry();
-    while (zipEntry != null)
+    while (zipEntry != null && !restoreConfig.isCancelled())
     {
       String name = zipEntry.getName();
 
@@ -1078,7 +1088,7 @@
         long totalBytesRead = 0;
         byte[] buffer = new byte[8192];
         int bytesRead = zipStream.read(buffer);
-        while (bytesRead > 0)
+        while (bytesRead > 0 && !restoreConfig.isCancelled())
         {
           totalBytesRead += bytesRead;
 
@@ -1153,7 +1163,8 @@
    * @throws IOException If an I/O error occurs while archiving the file.
    */
   private long archiveFile(ZipOutputStream zipStream,
-                           Mac mac, MessageDigest digest, File file)
+                           Mac mac, MessageDigest digest, File file,
+                           BackupConfig backupConfig)
        throws IOException, FileNotFoundException
   {
     ZipEntry zipEntry = new ZipEntry(file.getName());
@@ -1179,7 +1190,7 @@
     long totalBytesRead = 0;
     byte[] buffer = new byte[8192];
     int bytesRead = inputStream.read(buffer);
-    while (bytesRead > 0)
+    while (bytesRead > 0 && !backupConfig.isCancelled())
     {
       if (mac != null)
       {
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ExportJob.java b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ExportJob.java
index 4da7cbd..ba70918 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ExportJob.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ExportJob.java
@@ -143,6 +143,11 @@
     {
       for (EntryContainer exportContainer : exportContainers)
       {
+        if (exportConfig.isCancelled())
+        {
+          break;
+        }
+
         exportContainer.sharedLock.lock();
         try
         {
@@ -201,6 +206,11 @@
            status == OperationStatus.SUCCESS;
            status = cursor.getNext(key, data, LockMode.DEFAULT))
       {
+        if (exportConfig.isCancelled())
+        {
+          break;
+        }
+
         EntryID entryID = null;
         try
         {
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ImportJob.java b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ImportJob.java
index 9e7a270..1f4aba8 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ImportJob.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ImportJob.java
@@ -601,6 +601,11 @@
 
     do
     {
+      if (ldifImportConfig.isCancelled())
+      {
+        break;
+      }
+
       if(threads.size() <= 0)
       {
         message = ERR_JEB_IMPORT_NO_WORKER_THREADS.get();
@@ -674,7 +679,8 @@
         {
           status = cursor.getFirst(key, data, lockMode);
 
-          while(status == OperationStatus.SUCCESS)
+          while(status == OperationStatus.SUCCESS &&
+                !ldifImportConfig.isCancelled())
           {
             if(threads.size() <= 0)
             {
@@ -772,7 +778,8 @@
               end[0] = (byte) (end[0] + 1);
 
               while(status == OperationStatus.SUCCESS &&
-                  dn2idComparator.compare(key.getData(), end) < 0)
+                  dn2idComparator.compare(key.getData(), end) < 0 &&
+                  !ldifImportConfig.isCancelled())
               {
                 if(threads.size() <= 0)
                 {
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/task/Task.java b/opendj-sdk/opends/src/server/org/opends/server/backends/task/Task.java
index e26ec54..f4805bb 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/task/Task.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/task/Task.java
@@ -142,6 +142,9 @@
   // The current state of this task.
   private TaskState taskState;
 
+  // The task state that may be set when the task is interrupted.
+  private TaskState taskInterruptState;
+
   // The scheduler with which this task is associated.
   private TaskScheduler taskScheduler;
 
@@ -577,6 +580,18 @@
     return taskState;
   }
 
+  /**
+   * Indicates whether or not this task has been cancelled.
+   *
+   * @return boolean where true indicates that this task was
+   *         cancelled either before or during execution
+   */
+  public boolean isCancelled()
+  {
+    return taskInterruptState != null &&
+      TaskState.isCancelled(taskInterruptState);
+  }
+
 
 
   /**
@@ -626,6 +641,58 @@
     }
   }
 
+
+  /**
+   * Sets a state for this task that is the result of a call to
+   * {@link #interruptTask(TaskState, org.opends.messages.Message)}.
+   * It may take this task some time to actually cancel to that
+   * actual state may differ until quiescence.
+   *
+   * @param state for this task once it has canceled whatever it is doing
+   */
+  protected void setTaskInterruptState(TaskState state)
+  {
+    this.taskInterruptState = state;
+  }
+
+
+  /**
+   * Gets the interrupt state for this task that was set as a
+   * result of a call to {@link #interruptTask(TaskState,
+   * org.opends.messages.Message)}.
+   *
+   * @return interrupt state for this task
+   */
+  protected TaskState getTaskInterruptState()
+  {
+    return this.taskInterruptState;
+  }
+
+
+  /**
+   * Returns a state for this task after processing has completed.
+   * If the task was interrupted with a call to
+   * {@link #interruptTask(TaskState, org.opends.messages.Message)}
+   * then that method's interruptState is returned here.  Otherwse
+   * this method returns TaskState.COMPLETED_SUCCESSFULLY.  It is
+   * assumed that if there were errors during task processing that
+   * task state will have been derived in some other way.
+   *
+   * @return state for this task after processing has completed
+   */
+  protected TaskState getFinalTaskState()
+  {
+    if (this.taskInterruptState == null)
+    {
+      return TaskState.COMPLETED_SUCCESSFULLY;
+    }
+    else
+    {
+      return this.taskInterruptState;
+    }
+  }
+
+
   /**
    * Replaces an attribute values of the task entry.
    *
@@ -1241,6 +1308,10 @@
    * gracefully interrupt a task, then subclasses should override this method to
    * do so.
    *
+   * Implementations of this method are exprected to call
+   * {@link #setTaskInterruptState(TaskState)} if the interruption is accepted
+   * by this task.
+   *
    * @param  interruptState   The state to use for the task if it is
    *                          successfully interrupted.
    * @param  interruptReason  A human-readable explanation for the cancellation.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskState.java b/opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskState.java
index fb5dbaf..43c78a7 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskState.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskState.java
@@ -224,6 +224,26 @@
   }
 
 
+  /**
+   * Indicates whether or not this task has been cancelled.
+   *
+   * @param  taskState  The task state for which to make the determination.
+   *
+   * @return  <CODE>true</CODE> if the task state indicates that the task
+   *          was cancelled either before or during execution, or
+   *          <CODE>false</CODE> otherwise.
+   */
+  public static boolean isCancelled(TaskState taskState)
+  {
+    switch(taskState)
+    {
+      case STOPPED_BY_ADMINISTRATOR:
+      case CANCELED_BEFORE_STARTING:
+        return true;
+      default:
+        return false;
+    }
+  }
 
   /**
    * Retrieves the task state that corresponds to the provided string value.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java b/opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
index 61b6b32..658a352 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/extensions/ConfigFileHandler.java
@@ -2798,7 +2798,7 @@
       while (true)
       {
         int bytesRead = inputStream.read(buffer);
-        if (bytesRead < 0)
+        if (bytesRead < 0 || backupConfig.isCancelled())
         {
           break;
         }
@@ -2862,7 +2862,7 @@
           while (true)
           {
             int bytesRead = inputStream.read(buffer);
-            if (bytesRead < 0)
+            if (bytesRead < 0 || backupConfig.isCancelled())
             {
               break;
             }
@@ -2972,6 +2972,14 @@
       throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
                                    message, e);
     }
+
+    // Remove the backup if this operation was cancelled since the
+    // backup may be incomplete
+    if (backupConfig.isCancelled())
+    {
+      removeBackup(backupDirectory, backupID);
+    }
+
   }
 
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/replication/server/ReplicationBackend.java b/opendj-sdk/opends/src/server/org/opends/server/replication/server/ReplicationBackend.java
index fc2bb7c..a935278 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/replication/server/ReplicationBackend.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/replication/server/ReplicationBackend.java
@@ -505,6 +505,10 @@
     {
       for (ReplicationCache exportContainer : exportContainers)
       {
+        if (exportConfig.isCancelled())
+        {
+          break;
+        }
         processContainer(exportContainer, exportConfig, ldifWriter, null);
       }
     }
@@ -571,6 +575,11 @@
 
     for (ReplicationCache exportContainer : exportContainers)
     {
+      if (exportConfig != null && exportConfig.isCancelled())
+      {
+        break;
+      }
+
       attributes.clear();
       ldapAttrList.clear();
 
@@ -630,6 +639,11 @@
     // Walk through the servers
     for (Short serverId : rc.getServers())
     {
+      if (exportConfig != null && exportConfig.isCancelled())
+      {
+        break;
+      }
+
       ReplicationIterator ri = rc.getChangelogIterator(serverId,
           null);
 
@@ -640,6 +654,10 @@
           // Walk through the changes
           while (ri.getChange() != null)
           {
+            if (exportConfig != null && exportConfig.isCancelled())
+            {
+              break;
+            }
             UpdateMessage msg = ri.getChange();
             processChange(msg, exportConfig, ldifWriter, searchOperation);
             if (!ri.next())
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tasks/BackupTask.java b/opendj-sdk/opends/src/server/org/opends/server/tasks/BackupTask.java
index f9aba64..bfdce39 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tasks/BackupTask.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tasks/BackupTask.java
@@ -26,6 +26,7 @@
  */
 package org.opends.server.tasks;
 import org.opends.messages.Message;
+import org.opends.messages.TaskMessages;
 
 import static org.opends.server.config.ConfigConstants.*;
 import static org.opends.server.core.DirectoryServer.getAttributeType;
@@ -133,6 +134,8 @@
   private File    backupDirectory;
   private String  incrementalBase;
 
+  private BackupConfig backupConfig;
+
   /**
    * All the backend configuration entries defined in the server mapped
    * by their backend ID.
@@ -460,7 +463,7 @@
 
 
     // Create a backup configuration.
-    BackupConfig backupConfig = new BackupConfig(backupDir, backupID,
+    backupConfig = new BackupConfig(backupDir, backupID,
                                                  incremental);
     backupConfig.setCompressData(compress);
     backupConfig.setEncryptData(encrypt);
@@ -560,6 +563,30 @@
   /**
    * {@inheritDoc}
    */
+  public void interruptTask(TaskState interruptState, Message interruptReason)
+  {
+    if (TaskState.STOPPED_BY_ADMINISTRATOR.equals(interruptState) &&
+            backupConfig != null)
+    {
+      addLogMessage(TaskMessages.INFO_TASK_STOPPED_BY_ADMIN.get(
+              interruptReason));
+      setTaskInterruptState(interruptState);
+      backupConfig.cancel();
+    }
+  }
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isInterruptable() {
+    return true;
+  }
+
+
+  /**
+   * {@inheritDoc}
+   */
   protected TaskState runTask()
   {
     if (!argumentsAreValid())
@@ -585,6 +612,11 @@
     boolean errorsEncountered = false;
     for (Backend b : backendsToArchive)
     {
+      if (isCancelled())
+      {
+        break;
+      }
+
       // Acquire a shared lock for this backend.
       if (!lockBackend(b))
       {
@@ -639,6 +671,12 @@
       logError(message);
       return TaskState.COMPLETED_WITH_ERRORS;
     }
+    else if (isCancelled())
+    {
+      Message message = NOTE_BACKUPDB_CANCELLED.get();
+      logError(message);
+      return getTaskInterruptState();
+    }
     else
     {
       Message message = NOTE_BACKUPDB_COMPLETED_SUCCESSFULLY.get();
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tasks/ExportTask.java b/opendj-sdk/opends/src/server/org/opends/server/tasks/ExportTask.java
index 10432f5..2d9f58f 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tasks/ExportTask.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tasks/ExportTask.java
@@ -26,6 +26,7 @@
  */
 package org.opends.server.tasks;
 import org.opends.messages.Message;
+import org.opends.messages.TaskMessages;
 
 import static org.opends.server.core.DirectoryServer.getAttributeType;
 import static org.opends.server.config.ConfigConstants.*;
@@ -55,6 +56,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.HashMap;
+import java.io.File;
 
 /**
  * This class provides an implementation of a Directory Server task that can
@@ -136,6 +138,7 @@
   private ArrayList<String> includeBranchStrings;
   private ArrayList<String> excludeBranchStrings;
 
+  private LDIFExportConfig exportConfig;
 
   /**
    * {@inheritDoc}
@@ -259,6 +262,31 @@
 
   }
 
+
+  /**
+   * {@inheritDoc}
+   */
+  public void interruptTask(TaskState interruptState, Message interruptReason)
+  {
+    if (TaskState.STOPPED_BY_ADMINISTRATOR.equals(interruptState) &&
+            exportConfig != null)
+    {
+      addLogMessage(TaskMessages.INFO_TASK_STOPPED_BY_ADMIN.get(
+              interruptReason));
+      setTaskInterruptState(interruptState);
+      exportConfig.cancel();
+    }
+  }
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isInterruptable() {
+    return true;
+  }
+
+
   /**
    * {@inheritDoc}
    */
@@ -483,8 +511,7 @@
       existingBehavior = ExistingFileBehavior.OVERWRITE;
     }
 
-    LDIFExportConfig exportConfig =
-         new LDIFExportConfig(ldifFile, existingBehavior);
+    exportConfig = new LDIFExportConfig(ldifFile, existingBehavior);
     exportConfig.setCompressData(compressLDIF);
     exportConfig.setEncryptData(encryptLDIF);
     exportConfig.setExcludeAttributes(excludeAttributes);
@@ -587,7 +614,19 @@
       exportConfig.close();
     }
 
+    // If the operation was cancelled delete the export file since
+    // if will be incomplete.
+    if (exportConfig.isCancelled())
+    {
+      File f = new File(ldifFile);
+      if (f.exists())
+      {
+        f.delete();
+      }
+    }
 
-    return TaskState.COMPLETED_SUCCESSFULLY;
+    // If we got here the task either completed successfully or
+    // was interrupted
+    return getFinalTaskState();
   }
 }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tasks/ImportTask.java b/opendj-sdk/opends/src/server/org/opends/server/tasks/ImportTask.java
index 2d451dc..5b3410e 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tasks/ImportTask.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tasks/ImportTask.java
@@ -26,6 +26,7 @@
  */
 package org.opends.server.tasks;
 import org.opends.messages.Message;
+import org.opends.messages.TaskMessages;
 
 import static org.opends.messages.TaskMessages.*;
 import static org.opends.messages.ToolMessages.*;
@@ -169,6 +170,7 @@
   ArrayList<String>  includeFilterStrings    = null;
   ArrayList<String>  ldifFiles               = null;
 
+  private LDIFImportConfig importConfig;
 
   /**
    * {@inheritDoc}
@@ -482,6 +484,30 @@
   }
 
 
+  /**
+   * {@inheritDoc}
+   */
+  public void interruptTask(TaskState interruptState, Message interruptReason)
+  {
+    if (TaskState.STOPPED_BY_ADMINISTRATOR.equals(interruptState) &&
+            importConfig != null)
+    {
+      addLogMessage(TaskMessages.INFO_TASK_STOPPED_BY_ADMIN.get(
+              interruptReason));
+      setTaskInterruptState(interruptState);
+      importConfig.cancel();
+    }
+  }
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isInterruptable()
+  {
+    return true;
+  }
+
 
   /**
    * {@inheritDoc}
@@ -731,7 +757,7 @@
 
     // Create the LDIF import configuration to use when reading the LDIF.
     ArrayList<String> fileList = new ArrayList<String>(ldifFiles);
-    LDIFImportConfig importConfig = new LDIFImportConfig(fileList);
+    importConfig = new LDIFImportConfig(fileList);
     importConfig.setAppendToExistingData(append);
     importConfig.setReplaceExistingEntries(replaceExisting);
     importConfig.setCompressed(isCompressed);
@@ -942,6 +968,6 @@
 
     // Clean up after the import by closing the import config.
     importConfig.close();
-    return TaskState.COMPLETED_SUCCESSFULLY;
+    return getFinalTaskState();
   }
 }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tasks/RestoreTask.java b/opendj-sdk/opends/src/server/org/opends/server/tasks/RestoreTask.java
index b13858c..7b44ef8 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tasks/RestoreTask.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tasks/RestoreTask.java
@@ -26,6 +26,7 @@
  */
 package org.opends.server.tasks;
 import org.opends.messages.Message;
+import org.opends.messages.TaskMessages;
 
 import static org.opends.server.core.DirectoryServer.getAttributeType;
 import static org.opends.server.config.ConfigConstants.*;
@@ -100,6 +101,7 @@
   private String backupID;
   private boolean verifyOnly;
 
+  private RestoreConfig restoreConfig;
 
   /**
    * {@inheritDoc}
@@ -223,6 +225,31 @@
     return true;
   }
 
+
+  /**
+   * {@inheritDoc}
+   */
+  public void interruptTask(TaskState interruptState, Message interruptReason)
+  {
+    if (TaskState.STOPPED_BY_ADMINISTRATOR.equals(interruptState) &&
+            restoreConfig != null)
+    {
+      addLogMessage(TaskMessages.INFO_TASK_STOPPED_BY_ADMIN.get(
+              interruptReason));
+      setTaskInterruptState(interruptState);
+      restoreConfig.cancel();
+    }
+  }
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isInterruptable() {
+    return true;
+  }
+
+
   /**
    * {@inheritDoc}
    */
@@ -311,8 +338,7 @@
     }
 
     // Create the restore config object from the information available.
-    RestoreConfig restoreConfig = new RestoreConfig(backupDir, backupID,
-                                                    verifyOnly);
+    restoreConfig = new RestoreConfig(backupDir, backupID, verifyOnly);
 
     // Notify the task listeners that a restore is going to start
     // this must be done before disabling the backend to allow
@@ -408,7 +434,7 @@
     }
     else
     {
-      return TaskState.COMPLETED_SUCCESSFULLY;
+      return getFinalTaskState();
     }
   }
 }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/BackupConfig.java b/opendj-sdk/opends/src/server/org/opends/server/types/BackupConfig.java
index 6ceb0c4..83876c0 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/types/BackupConfig.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/BackupConfig.java
@@ -49,7 +49,7 @@
      mayInstantiate=true,
      mayExtend=false,
      mayInvoke=true)
-public final class BackupConfig
+public final class BackupConfig extends OperationConfig
 {
   // The path to the directory in which the backup file(s) should be
   // created.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/LDIFExportConfig.java b/opendj-sdk/opends/src/server/org/opends/server/types/LDIFExportConfig.java
index 5e3618a..2d0d560 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/types/LDIFExportConfig.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/LDIFExportConfig.java
@@ -56,7 +56,7 @@
      mayInstantiate=true,
      mayExtend=false,
      mayInvoke=true)
-public final class LDIFExportConfig
+public final class LDIFExportConfig extends OperationConfig
 {
   /**
    * The tracer object for the debug logger.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/LDIFImportConfig.java b/opendj-sdk/opends/src/server/org/opends/server/types/LDIFImportConfig.java
index f689520..416a675 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/types/LDIFImportConfig.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/LDIFImportConfig.java
@@ -64,7 +64,7 @@
      mayInstantiate=true,
      mayExtend=false,
      mayInvoke=true)
-public final class LDIFImportConfig
+public final class LDIFImportConfig extends OperationConfig
 {
   /**
    * The tracer object for the debug logger.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/OperationConfig.java b/opendj-sdk/opends/src/server/org/opends/server/types/OperationConfig.java
new file mode 100644
index 0000000..2dd79e3
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/OperationConfig.java
@@ -0,0 +1,66 @@
+/*
+ * 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
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * 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
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  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
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.types;
+
+/**
+ * Base for data structures that define configuration
+ * for operations.
+ */
+@org.opends.server.types.PublicAPI(
+     stability=org.opends.server.types.StabilityLevel.VOLATILE,
+     mayInstantiate=true,
+     mayExtend=false,
+     mayInvoke=true)
+public abstract class OperationConfig {
+
+  // When true indicates that the operation should stop as soon as
+  // possible.
+  private boolean cancelled;
+
+  /**
+   * Indicates that this operation has been cancelled and the
+   * operation if executing should finish as soon as possible.
+   */
+  public void cancel()
+  {
+    this.cancelled = true;
+  }
+
+  /**
+   * Indicates whether or not this operation has been
+   * cancelled.
+   *
+   * @return boolean where true indicates that this
+   *         operation has been cancelled and if currently
+   *         executing will finish as soon as possible
+   */
+  public boolean isCancelled()
+  {
+    return this.cancelled;
+  }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/RestoreConfig.java b/opendj-sdk/opends/src/server/org/opends/server/types/RestoreConfig.java
index 86cf65b..104acf8 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/types/RestoreConfig.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/RestoreConfig.java
@@ -47,7 +47,7 @@
      mayInstantiate=true,
      mayExtend=false,
      mayInvoke=true)
-public final class RestoreConfig
+public final class RestoreConfig extends OperationConfig
 {
   // The reference to the directory containing the backup file(s) to
   // restore.

--
Gitblit v1.10.0