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 }