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 }