opendj-sdk/opends/resource/schema/02-config.ldif
@@ -1553,6 +1553,10 @@ attributeTypes: ( 1.3.6.1.4.1.26027.1.1.464 NAME 'ds-rlim-idle-time-limit' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'OpenDS Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.26027.1.1.465 NAME 'ds-cfg-notification-sender-address' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.1 NAME 'ds-cfg-access-control-handler' SUP top STRUCTURAL MUST ( cn $ ds-cfg-acl-handler-class $ ds-cfg-acl-handler-enabled ) @@ -1622,7 +1626,8 @@ X-ORIGIN 'OpenDS Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.10 NAME 'ds-cfg-task-backend' SUP ds-cfg-backend STRUCTURAL MAY ( ds-cfg-task-backing-file $ ds-cfg-task-retention-time ) X-ORIGIN 'OpenDS Directory Server' ) ds-cfg-task-retention-time $ ds-cfg-notification-sender-address ) X-ORIGIN 'OpenDS Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.11 NAME 'ds-cfg-branch' SUP top STRUCTURAL MUST cn X-ORIGIN 'OpenDS Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.12 opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/TaskBackendConfiguration.xml
@@ -31,6 +31,7 @@ extends="backend" xmlns:adm="http://www.opends.org/admin" xmlns:ldap="http://www.opends.org/admin-ldap"> <adm:synopsis> The task backend provides a mechanism for processing tasks in the OpenDS Directory Server. Tasks are intended to provide access to certain @@ -51,6 +52,7 @@ The org.opends.server.backends.task.TaskBackend class provides the entry point for the task backend implementation. </adm:description> <adm:profile name="ldap"> <ldap:object-class> <ldap:oid>1.3.6.1.4.1.26027.1.2.10</ldap:oid> @@ -58,6 +60,7 @@ <ldap:superior>ds-cfg-backend</ldap:superior> </ldap:object-class> </adm:profile> <adm:property-override name="backend-class"> <adm:default-behavior> <adm:defined> @@ -67,6 +70,7 @@ </adm:defined> </adm:default-behavior> </adm:property-override> <adm:property name="task-backing-file" mandatory="true" multi-valued="false"> @@ -86,6 +90,7 @@ </ldap:attribute> </adm:profile> </adm:property> <adm:property name="task-retention-time" mandatory="false" multi-valued="false"> @@ -108,4 +113,34 @@ </ldap:attribute> </adm:profile> </adm:property> <adm:property name="notification-sender-address" mandatory="false" multi-valued="false"> <adm:synopsis> This specifies the e-mail address to use as the sender (i.e., "From:") address for notification mail messages generated when a task completes execution. </adm:synopsis> <adm:default-behavior> <adm:alias> <adm:synopsis> The default sender address used will be "opends-task-notification@" followed by the canonical address of the system on which the server is running. </adm:synopsis> </adm:alias> </adm:default-behavior> <adm:syntax> <adm:string /> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.465</ldap:oid> <ldap:name>ds-cfg-notification-sender-address</ldap:name> </ldap:attribute> </adm:profile> </adm:property> </adm:managed-object> opendj-sdk/opends/src/server/org/opends/server/backends/task/Task.java
@@ -38,12 +38,16 @@ import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.locks.Lock; import javax.mail.MessagingException; import org.opends.server.core.DirectoryServer; import org.opends.server.loggers.ErrorLogger; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.protocols.asn1.ASN1OctetString; import org.opends.server.types.Attribute; import org.opends.server.types.AttributeType; import org.opends.server.types.AttributeValue; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.DirectoryException; import org.opends.server.types.DN; import org.opends.server.types.Entry; @@ -51,16 +55,13 @@ import org.opends.server.types.ErrorLogSeverity; import org.opends.server.types.InitializationException; import org.opends.server.types.Operation; import org.opends.server.util.EMailMessage; import org.opends.server.util.TimeThread; import static org.opends.server.config.ConfigConstants.*; import static org.opends.server.loggers.debug.DebugLogger.*; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.loggers.ErrorLogger; import org.opends.server.types.DebugLogLevel; import static org.opends.server.messages.BackendMessages.*; import static org.opends.server.messages.MessageHandler.*; import org.opends.server.messages.MessageHandler; import static org.opends.server.util.ServerConstants.*; import static org.opends.server.util.StaticUtils.*; @@ -125,6 +126,9 @@ // The unique ID assigned to this task. private String taskID; // The task backend with which this task is associated. private TaskBackend taskBackend; // The current state of this task. private TaskState taskState; @@ -153,6 +157,7 @@ String taskDN = taskEntryDN.toString(); taskBackend = taskScheduler.getTaskBackend(); logMessageCounter = 0; @@ -787,6 +792,8 @@ return logMessages; } /** * Writes a message to the error log using the provided information. * Tasks should use this method to log messages to the error log instead of @@ -800,12 +807,11 @@ * @param errorID The error ID that uniquely identifies the provided format * string. */ protected void logError(ErrorLogCategory category, ErrorLogSeverity severity, int errorID) protected void logError(ErrorLogCategory category, ErrorLogSeverity severity, int errorID) { String message = MessageHandler.getMessage(errorID); addLogMessage(severity, errorID, message); // Simply pass this on to the server error logger, and it will call back // to the addLogMessage method for this task. ErrorLogger.logError(category, severity, errorID); } @@ -826,13 +832,11 @@ * @param args The set of arguments to use for the provided format * string. */ protected void logError(ErrorLogCategory category, ErrorLogSeverity severity, int errorID, Object... args) protected void logError(ErrorLogCategory category, ErrorLogSeverity severity, int errorID, Object... args) { String message = MessageHandler.getMessage(errorID); addLogMessage(severity, errorID, message); // Simply pass this on to the server error logger, and it will call back // to the addLogMessage method for this task. ErrorLogger.logError(category, severity, errorID,args); } @@ -852,26 +856,27 @@ * @param errorID The error ID that uniquely identifies the format string * used to generate the provided message. */ protected void logError(ErrorLogCategory category, ErrorLogSeverity severity, String message, int errorID) protected void logError(ErrorLogCategory category, ErrorLogSeverity severity, String message, int errorID) { addLogMessage(severity, errorID, message); ErrorLogger.logError(category, severity, message, errorID); // Simply pass this on to the server error logger, and it will call back // to the addLogMessage method for this task. ErrorLogger.logError(category, severity, message, errorID); } /** * Adds a log message to the set of messages logged by this task. This method * should not be called directly by tasks, but rather will be called * indirectly through the logError methods in this class. It does not * indirectly through the {@code ErrorLog.logError} methods. It does not * automatically persist the updated task information to disk. * * @param severity The severity level for the log message. * @param messageID The ID that uniquely identifies the log message. * @param messageString The text of the log message */ void addLogMessage(ErrorLogSeverity severity, int messageID, public void addLogMessage(ErrorLogSeverity severity, int messageID, String messageString) { Lock lock = taskScheduler.writeLockEntry(taskEntryDN); @@ -1067,8 +1072,8 @@ int msgID = MSGID_TASK_EXECUTE_FAILED; String message = getMessage(msgID, String.valueOf(taskEntry.getDN()), stackTraceToSingleLineString(e)); logError(ErrorLogCategory.TASK, ErrorLogSeverity.SEVERE_ERROR, message, msgID); ErrorLogger.logError(ErrorLogCategory.TASK, ErrorLogSeverity.SEVERE_ERROR, message, msgID); } finally { @@ -1076,13 +1081,81 @@ taskScheduler.writeState(); } // FIXME -- Send an e-mail message if appropriate. try { sendNotificationEMailMessage(); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } } return taskState; } /** * If appropriate, send an e-mail message with information about the * completed task. * * @throws MessagingException If a problem occurs while attempting to send * the message. */ private void sendNotificationEMailMessage() throws MessagingException { if (DirectoryServer.mailServerConfigured()) { LinkedHashSet<String> recipients = new LinkedHashSet<String>(); recipients.addAll(notifyOnCompletion); if (! TaskState.isSuccessful(taskState)) { recipients.addAll(notifyOnError); } if (! recipients.isEmpty()) { EMailMessage message = new EMailMessage(taskBackend.getNotificationSenderAddress(), new ArrayList<String>(recipients), taskState.toString() + " " + taskID); String scheduledStartDate; if (scheduledStartTime <= 0) { scheduledStartDate = ""; } else { scheduledStartDate = new Date(scheduledStartTime).toString(); } String actualStartDate = new Date(actualStartTime).toString(); String completionDate = new Date(completionTime).toString(); message.setBody(getMessage(MSGID_TASK_COMPLETION_BODY, taskID, String.valueOf(taskState), scheduledStartDate, actualStartDate, completionDate)); for (String logMessage : logMessages) { message.appendToBody(logMessage); message.appendToBody("\r\n"); } message.send(); } } } /** * Performs any task-specific initialization that may be required before * processing can start. This default implementation does not do anything, * but subclasses may override it as necessary. This method will be called at opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskBackend.java
@@ -29,6 +29,7 @@ import java.io.File; import java.net.InetAddress; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -116,6 +117,9 @@ // removed from the set of scheduled tasks. private long retentionTime; // The e-mail address to use for the sender from notification messages. private String notificationSenderAddress; // The path to the task backing file. private String taskBackingFile; @@ -226,6 +230,22 @@ retentionTime = cfg.getTaskRetentionTime(); // Get the notification sender address. notificationSenderAddress = cfg.getNotificationSenderAddress(); if (notificationSenderAddress == null) { try { notificationSenderAddress = "opends-task-notification@" + InetAddress.getLocalHost().getCanonicalHostName(); } catch (Exception e) { notificationSenderAddress = "opends-task-notification@opends.org"; } } // Get the path to the task data backing file. taskBackingFile = cfg.getTaskBackingFile(); @@ -1285,6 +1305,22 @@ } String tmpNotificationAddress = configEntry.getNotificationSenderAddress(); if (tmpNotificationAddress == null) { try { tmpNotificationAddress = "opends-task-notification@" + InetAddress.getLocalHost().getCanonicalHostName(); } catch (Exception e) { tmpNotificationAddress = "opends-task-notification@opends.org"; } } notificationSenderAddress = tmpNotificationAddress; currentConfig = configEntry; return new ConfigChangeResult(resultCode, adminActionRequired, messages); } @@ -1319,6 +1355,20 @@ /** * Retrieves the sender address that should be used for e-mail notifications * of task completion. * * @return The sender address that should be used for e-mail notifications of * task completion. */ public String getNotificationSenderAddress() { return notificationSenderAddress; } /** * Retrieves the length of time in seconds that information for a task should * be retained after processing on it has completed. * opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskScheduler.java
@@ -1357,6 +1357,18 @@ /** * Retrieves the task backend with which this scheduler is associated. * * @return The task backend with which this scheduler is associated. */ public TaskBackend getTaskBackend() { return taskBackend; } /** * Retrieves the root entry that is the common ancestor for all entries in the * task backend. * opendj-sdk/opends/src/server/org/opends/server/backends/task/TaskThread.java
@@ -29,11 +29,13 @@ import org.opends.server.api.DirectoryThread; import org.opends.server.types.ErrorLogSeverity; import static org.opends.server.loggers.debug.DebugLogger.*; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.ErrorLogCategory; import org.opends.server.types.ErrorLogSeverity; import static org.opends.server.loggers.ErrorLogger.*; import static org.opends.server.loggers.debug.DebugLogger.*; import static org.opends.server.messages.BackendMessages.*; import static org.opends.server.messages.MessageHandler.*; import static org.opends.server.util.StaticUtils.*; @@ -41,6 +43,7 @@ import java.util.Map; /** * This class defines a thread that will be used to execute a scheduled task * within the server and provide appropriate notification that the task is @@ -56,16 +59,12 @@ // Indicates whether a request has been made for this thread to exit. private boolean exitRequested; // The thread ID for this task thread. private int threadID; // The task currently being processed by this thread. private Task task; // The reference to the scheduler with which this thread is associated. private TaskScheduler taskScheduler; @@ -90,9 +89,10 @@ this.taskScheduler = taskScheduler; this.threadID = threadID; task = null; notifyLock = new Object(); exitRequested = false; setAssociatedTask(null); } @@ -106,7 +106,7 @@ */ public Task getTask() { return task; return getAssociatedTask(); } @@ -119,7 +119,7 @@ */ public void setTask(Task task) { this.task = task; setAssociatedTask(task); synchronized (notifyLock) { @@ -142,11 +142,11 @@ public void interruptTask(TaskState interruptState, String interruptReason, boolean exitThread) { if (task != null) if (getAssociatedTask() != null) { try { task.interruptTask(interruptState, interruptReason); getAssociatedTask().interruptTask(interruptState, interruptReason); } catch (Exception e) { @@ -173,7 +173,7 @@ { while (! exitRequested) { if (task == null) if (getAssociatedTask() == null) { try { @@ -195,8 +195,8 @@ try { TaskState returnState = task.execute(); task.setTaskState(returnState); TaskState returnState = getAssociatedTask().execute(); getAssociatedTask().setTaskState(returnState); } catch (Exception e) { @@ -205,17 +205,20 @@ TRACER.debugCaught(DebugLogLevel.ERROR, e); } Task task = getAssociatedTask(); int msgID = MSGID_TASK_EXECUTE_FAILED; String message = getMessage(msgID, String.valueOf(task.getTaskEntry().getDN()), stackTraceToSingleLineString(e)); task.addLogMessage(ErrorLogSeverity.FATAL_ERROR, msgID, message); logError(ErrorLogCategory.TASK, ErrorLogSeverity.FATAL_ERROR, message, msgID); task.setTaskState(TaskState.STOPPED_BY_ERROR); } Task completedTask = task; task = null; Task completedTask = getAssociatedTask(); setAssociatedTask(null); if (! taskScheduler.threadDone(this, completedTask)) { exitRequested = true; @@ -223,13 +226,16 @@ } } if (task != null) if (getAssociatedTask() != null) { Task task = getAssociatedTask(); task.setTaskState(TaskState.STOPPED_BY_SHUTDOWN); taskScheduler.threadDone(this, task); } } /** * Retrieves any relevent debug information with which this tread is * associated so they can be included in debug messages. @@ -239,7 +245,11 @@ public Map<String, String> getDebugProperties() { Map<String, String> properties = super.getDebugProperties(); properties.put("task", task.toString()); if (getAssociatedTask() != null) { properties.put("task", getAssociatedTask().toString()); } return properties; } opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -2058,6 +2058,21 @@ /** * Indicates whether the Directory Server is configured with information about * one or more mail servers and may therefore be used to send e-mail messages. * * @return {@code true} if the Directory Server is configured to be able to * send e-mail messages, or {@code false} if not. */ public static boolean mailServerConfigured() { return ((directoryServer.mailServerPropertySets != null) && (! directoryServer.mailServerPropertySets.isEmpty())); } /** * Specifies the set of mail server properties that should be used for SMTP * communication. * opendj-sdk/opends/src/server/org/opends/server/loggers/ErrorLogger.java
@@ -34,7 +34,10 @@ import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; import org.opends.server.api.DirectoryThread; import org.opends.server.api.ErrorLogPublisher; import org.opends.server.backends.task.Task; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.messages.MessageHandler; import org.opends.server.types.*; import org.opends.server.admin.std.server.ErrorLogPublisherCfg; @@ -47,7 +50,6 @@ import org.opends.server.core.DirectoryServer; import static org.opends.server.loggers.debug.DebugLogger.*; import org.opends.server.loggers.debug.DebugTracer; import static org.opends.server.messages.ConfigMessages.*; import static org.opends.server.util.StaticUtils.*; import static org.opends.server.messages.MessageHandler.getMessage; @@ -441,6 +443,16 @@ { publisher.logError(category, severity, message, errorID); } if (Thread.currentThread() instanceof DirectoryThread) { DirectoryThread thread = (DirectoryThread) Thread.currentThread(); Task task = thread.getAssociatedTask(); if (task != null) { task.addLogMessage(severity, errorID, message); } } } @@ -467,6 +479,16 @@ { publisher.logError(category, severity, message, errorID); } if (Thread.currentThread() instanceof DirectoryThread) { DirectoryThread thread = (DirectoryThread) Thread.currentThread(); Task task = thread.getAssociatedTask(); if (task != null) { task.addLogMessage(severity, errorID, message); } } } @@ -490,6 +512,16 @@ { publisher.logError(category, severity, message, errorID); } if (Thread.currentThread() instanceof DirectoryThread) { DirectoryThread thread = (DirectoryThread) Thread.currentThread(); Task task = thread.getAssociatedTask(); if (task != null) { task.addLogMessage(severity, errorID, message); } } } } opendj-sdk/opends/src/server/org/opends/server/messages/BackendMessages.java
@@ -3237,6 +3237,17 @@ /** * The message ID for the message that will be used as the body of the * notification e-mail message sent when a task is completed. It takes * five arguments, which are string representations of the task ID, task * state, scheduled start date, actual start date, and completion date. */ public static final int MSGID_TASK_COMPLETION_BODY = CATEGORY_MASK_BACKEND | SEVERITY_MASK_INFORMATIONAL | 299; /** * Associates a set of generic messages with the message IDs defined in this * class. */ @@ -3993,6 +4004,14 @@ registerMessage(MSGID_TASK_EXECUTE_FAILED, "An error occurred while executing the task defined in " + "entry %s: %s"); registerMessage(MSGID_TASK_COMPLETION_BODY, "Task ID: %s\r\n" + "Task State: %s\r\n" + "Scheduled Start Time: %s\r\n" + "Actual Start Time: %s\r\n" + "Completion Time: %s\r\n" + "\r\n" + "Log Messages:\r\n"); registerMessage(MSGID_RECURRINGTASK_NO_ID_ATTRIBUTE,