001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.core;
028    
029    import static org.opends.messages.CoreMessages.*;
030    import org.opends.messages.Message;
031    import static org.opends.server.util.Validator.ensureNotNull;
032    
033    import java.util.Collection;
034    import java.util.TreeMap;
035    
036    import org.opends.server.types.*;
037    import org.opends.server.workflowelement.WorkflowElement;
038    
039    
040    /**
041     * This class implements the workflow interface. Each task in the workflow
042     * is implemented by a WorkflowElement. All the tasks in the workflow are
043     * structured in a tree of tasks and the root node of the task tree is
044     * stored in the Workflow class itself. To execute a workflow, one just need
045     * to call the execute method on the root node of the task tree. Then each
046     * task in turn will execute its subordinate nodes and synchronizes them
047     * as needed.
048     */
049    public class WorkflowImpl implements Workflow
050    {
051      // The workflow identifier used by the configuration.
052      private String workflowID = null;
053    
054      // The root of the workflow task tree.
055      private WorkflowElement rootWorkflowElement = null;
056    
057      // The base DN of the data handled by the workflow.
058      private DN baseDN = null;
059    
060      // Flag indicating whether the workflow root node of the task tree is
061      // handling a private local backend.
062      //
063      // A private local backend is used by the server to store "private data"
064      // such as schemas, tasks, monitoring data, configuration data... Such
065      // private data are not returned upon a subtree search on the root DSE.
066      // Also it is not planned to have anything but a single node task tree
067      // to handle private local backend. So workflows used for proxy and
068      // virtual will always be made public (ie. not private). So, unless the
069      // rootWorkflowElement is handling a private local backend, the isPrivate
070      // flag will always return false.
071      private boolean isPrivate = false;
072    
073      // The set of workflows registered with the server.
074      private static TreeMap<String, Workflow> registeredWorkflows =
075        new TreeMap<String, Workflow>();
076    
077      // A lock to protect concurrent access to the registeredWorkflows.
078      private static Object registeredWorkflowsLock = new Object();
079    
080    
081      /**
082       * Creates a new instance of a workflow implementation. To define a worfklow
083       * one needs to provide a task tree root node (the rootWorkflowElement) and
084       * a base DN to identify the data set upon which the tasks can be applied.
085       *
086       * The rootWorkflowElement must not be null.
087       *
088       * @param workflowId          workflow internal identifier
089       * @param baseDN              identifies the data handled by the workflow
090       * @param rootWorkflowElement the root node of the workflow task tree
091       */
092      public WorkflowImpl(
093          String          workflowId,
094          DN              baseDN,
095          WorkflowElement rootWorkflowElement
096          )
097      {
098        this.workflowID = workflowId;
099        this.baseDN = baseDN;
100        this.rootWorkflowElement = rootWorkflowElement;
101        if (this.rootWorkflowElement != null)
102        {
103          this.isPrivate = rootWorkflowElement.isPrivate();
104        }
105      }
106    
107    
108      /**
109       * Performs any finalization that might be required when this
110       * workflow is unloaded.  No action is taken in the default
111       * implementation.
112       */
113      public void finalizeWorkflow()
114      {
115        // No action is required by default.
116      }
117    
118    
119      /**
120       * Gets the base DN of the data set being handled by the workflow.
121       *
122       * @return the workflow base DN
123       */
124      public DN getBaseDN()
125      {
126        return baseDN;
127      }
128    
129    
130      /**
131       * Gets the workflow internal identifier.
132       *
133       * @return the workflow internal indentifier
134       */
135      public String getWorkflowId()
136      {
137        return workflowID;
138      }
139    
140    
141      /**
142       * Indicates whether the root node of the workflow task tree is
143       * handling a private local backend.
144       *
145       * @return <code>true</code> if the workflow encapsulates a private local
146       *         backend
147       */
148      public boolean isPrivate()
149      {
150        return isPrivate;
151      }
152    
153    
154      /**
155       * Executes all the tasks defined by the workflow task tree for a given
156       * operation.
157       *
158       * @param operation  the operation to execute
159       *
160       * @throws CanceledOperationException if this operation should
161       * be cancelled.
162       */
163      public void execute(Operation operation) throws CanceledOperationException {
164        rootWorkflowElement.execute(operation);
165      }
166    
167    
168      /**
169       * Registers the current worklow (this) with the server.
170       *
171       * @throws  DirectoryException  If the workflow ID for the provided workflow
172       *                              conflicts with the workflow ID of an existing
173       *                              workflow.
174       */
175      public void register()
176          throws DirectoryException
177      {
178        ensureNotNull(workflowID);
179    
180        synchronized (registeredWorkflowsLock)
181        {
182          // The workflow must not be already registered
183          if (registeredWorkflows.containsKey(workflowID))
184          {
185            Message message =
186                    ERR_REGISTER_WORKFLOW_ALREADY_EXISTS.get(workflowID);
187            throw new DirectoryException(
188                ResultCode.UNWILLING_TO_PERFORM, message);
189          }
190    
191          TreeMap<String, Workflow> newRegisteredWorkflows =
192            new TreeMap<String, Workflow>(registeredWorkflows);
193          newRegisteredWorkflows.put(workflowID, this);
194          registeredWorkflows = newRegisteredWorkflows;
195        }
196      }
197    
198    
199      /**
200       * Deregisters the current worklow (this) with the server.
201       */
202      public void deregister()
203      {
204        ensureNotNull(workflowID);
205    
206        synchronized (registeredWorkflowsLock)
207        {
208          TreeMap<String, Workflow> newWorkflows =
209            new TreeMap<String, Workflow>(registeredWorkflows);
210          newWorkflows.remove(workflowID);
211          registeredWorkflows = newWorkflows;
212        }
213      }
214    
215    
216      /**
217       * Deregisters a worklow with the server. The workflow to deregister
218       * is identified with its identifier.
219       *
220       * @param workflowID  the identifier of the workflow to deregister
221       *
222       * @return the workflow that has been deregistered,
223       *         <code>null</code> if no workflow has been found.
224       */
225      public WorkflowImpl deregister(String workflowID)
226      {
227        WorkflowImpl workflowToDeregister = null;
228    
229        synchronized (registeredWorkflowsLock)
230        {
231          if (registeredWorkflows.containsKey(workflowID))
232          {
233            workflowToDeregister =
234              (WorkflowImpl) registeredWorkflows.get(workflowID);
235            workflowToDeregister.deregister();
236          }
237        }
238    
239        return workflowToDeregister;
240      }
241    
242    
243      /**
244       * Deregisters all Workflows that have been registered.  This should be
245       * called when the server is shutting down.
246       */
247      public static void deregisterAllOnShutdown()
248      {
249        synchronized (registeredWorkflowsLock)
250        {
251          registeredWorkflows =
252            new TreeMap<String, Workflow>();
253        }
254      }
255    
256    
257      /**
258       * Gets a workflow that was registered with the server.
259       *
260       * @param workflowID  the ID of the workflow to get
261       * @return the requested workflow
262       */
263      public static Workflow getWorkflow(
264          String workflowID)
265      {
266        return registeredWorkflows.get(workflowID);
267      }
268    
269    
270      /**
271       * Gets all the workflows that were registered with the server.
272       *
273       * @return the list of registered workflows
274       */
275      public static Collection<Workflow> getWorkflows()
276      {
277        return registeredWorkflows.values();
278      }
279    
280    
281      /**
282       * Gets the root workflow element for test purpose only.
283       *
284       * @return the root workflow element.
285       */
286      WorkflowElement getRootWorkflowElement()
287      {
288        return rootWorkflowElement;
289      }
290    
291    
292      /**
293       * Resets all the registered workflows.
294       */
295      public static void resetConfig()
296      {
297        synchronized (registeredWorkflowsLock)
298        {
299          registeredWorkflows = new TreeMap<String, Workflow>();
300        }
301      }
302    
303    }