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 2007-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.core;
028    
029    
030    
031    import java.util.ArrayList;
032    import java.util.List;
033    import java.util.concurrent.ConcurrentHashMap;
034    
035    import org.opends.messages.Message;
036    import org.opends.server.admin.server.ConfigurationAddListener;
037    import org.opends.server.admin.server.ConfigurationChangeListener;
038    import org.opends.server.admin.server.ConfigurationDeleteListener;
039    import org.opends.server.admin.server.ServerManagementContext;
040    import org.opends.server.admin.std.server.RootCfg;
041    import org.opends.server.admin.std.server.WorkflowCfg;
042    import org.opends.server.config.ConfigException;
043    import org.opends.server.types.ConfigChangeResult;
044    import org.opends.server.types.DN;
045    import org.opends.server.types.DirectoryException;
046    import org.opends.server.types.ResultCode;
047    import org.opends.server.workflowelement.WorkflowElement;
048    
049    
050    /**
051     * This class defines a utility that will be used to manage the configuration
052     * for the set of workflows defined in the Directory Server.  It will perform
053     * the necessary initialization of those workflows when the server is first
054     * started, and then will manage any changes to them while the server is
055     * running.
056     */
057    public class WorkflowConfigManager
058           implements ConfigurationChangeListener<WorkflowCfg>,
059                      ConfigurationAddListener<WorkflowCfg>,
060                      ConfigurationDeleteListener<WorkflowCfg>
061    
062    {
063      // A mapping between the DNs of the config entries and the associated
064      // workflows.
065      private ConcurrentHashMap<DN, WorkflowImpl> workflows;
066    
067    
068    
069      /**
070       * Creates a new instance of this workflow config manager.
071       */
072      public WorkflowConfigManager()
073      {
074        workflows = new ConcurrentHashMap<DN, WorkflowImpl>();
075      }
076    
077    
078    
079      /**
080       * Initializes all workflows currently defined in the Directory
081       * Server configuration.  This should only be called at Directory Server
082       * startup.
083       *
084       * @throws  ConfigException  If a configuration problem causes the workflow
085       *                           initialization process to fail.
086       */
087      public void initializeWorkflows()
088          throws ConfigException
089      {
090        // Get the root configuration object.
091        ServerManagementContext managementContext =
092             ServerManagementContext.getInstance();
093        RootCfg rootConfiguration =
094             managementContext.getRootConfiguration();
095    
096    
097        // Register as an add and delete listener with the root configuration so we
098        // can be notified if any workflow entries are added or removed.
099        rootConfiguration.addWorkflowAddListener(this);
100        rootConfiguration.addWorkflowDeleteListener(this);
101    
102    
103        //Initialize the existing workflows.
104        for (String workflowName : rootConfiguration.listWorkflows())
105        {
106          WorkflowCfg workflowConfiguration =
107            rootConfiguration.getWorkflow(workflowName);
108          workflowConfiguration.addChangeListener(this);
109    
110          if (workflowConfiguration.isEnabled())
111          {
112            try
113            {
114              createAndRegisterWorkflow(workflowConfiguration);
115            }
116            catch (DirectoryException de)
117            {
118              throw new ConfigException(de.getMessageObject());
119            }
120          }
121        }
122      }
123    
124    
125    
126      /**
127       * {@inheritDoc}
128       */
129      public boolean isConfigurationAddAcceptable(
130          WorkflowCfg   configuration,
131          List<Message> unacceptableReasons)
132      {
133        // Nothing to check.
134        return true;
135      }
136    
137    
138    
139      /**
140       * {@inheritDoc}
141       */
142      public ConfigChangeResult applyConfigurationAdd(
143          WorkflowCfg configuration)
144      {
145        ResultCode         resultCode          = ResultCode.SUCCESS;
146        boolean            adminActionRequired = false;
147        ArrayList<Message> messages            = new ArrayList<Message>();
148    
149        configuration.addChangeListener(this);
150    
151        // If the new network group is enabled then create it and register it.
152        if (configuration.isEnabled())
153        {
154          try
155          {
156            createAndRegisterWorkflow(configuration);
157          }
158          catch (DirectoryException de)
159          {
160            if (resultCode == ResultCode.SUCCESS)
161            {
162              resultCode = DirectoryServer.getServerErrorResultCode();
163            }
164    
165            messages.add(de.getMessageObject());
166          }
167        }
168    
169        return new ConfigChangeResult(resultCode, adminActionRequired, messages);
170      }
171    
172    
173    
174      /**
175       * {@inheritDoc}
176       */
177      public boolean isConfigurationDeleteAcceptable(
178          WorkflowCfg   configuration,
179          List<Message> unacceptableReasons)
180      {
181        return true;
182      }
183    
184    
185    
186      /**
187       * {@inheritDoc}
188       */
189      public ConfigChangeResult applyConfigurationDelete(
190          WorkflowCfg configuration)
191      {
192        ResultCode         resultCode          = ResultCode.SUCCESS;
193        boolean            adminActionRequired = false;
194        ArrayList<Message> messages            = new ArrayList<Message>();
195    
196    
197        WorkflowImpl workflow = workflows.remove(configuration.dn());
198        if (workflow != null)
199        {
200          workflow.deregister();
201          workflow.finalizeWorkflow();
202        }
203    
204        return new ConfigChangeResult(resultCode, adminActionRequired, messages);
205      }
206    
207    
208    
209      /**
210       * {@inheritDoc}
211       */
212      public boolean isConfigurationChangeAcceptable(
213          WorkflowCfg   configuration,
214          List<Message> unacceptableReasons)
215      {
216        // Nothing to check.
217        return true;
218      }
219    
220    
221    
222      /**
223       * {@inheritDoc}
224       */
225      public ConfigChangeResult applyConfigurationChange(
226          WorkflowCfg configuration)
227      {
228        ResultCode         resultCode          = ResultCode.SUCCESS;
229        boolean            adminActionRequired = false;
230        ArrayList<Message> messages            = new ArrayList<Message>();
231    
232        ConfigChangeResult configChangeResult =
233          new ConfigChangeResult(resultCode, adminActionRequired, messages);
234    
235    
236        // Get the existing network group if it's already enabled.
237        WorkflowImpl existingWorkflow = workflows.get(configuration.dn());
238    
239        // If the new configuration has the validator disabled, then disable it if
240        // it is enabled, or do nothing if it's already disabled.
241        if (! configuration.isEnabled())
242        {
243          if (existingWorkflow != null)
244          {
245            workflows.remove(configuration.dn());
246            existingWorkflow.deregister();
247            existingWorkflow.finalizeWorkflow();
248          }
249    
250          return configChangeResult;
251        }
252    
253        // If the network group is disabled then create and register it.
254        if (existingWorkflow == null)
255        {
256          try
257          {
258            createAndRegisterWorkflow(configuration);
259          }
260          catch (DirectoryException de)
261          {
262            if (resultCode == ResultCode.SUCCESS)
263            {
264              resultCode = DirectoryServer.getServerErrorResultCode();
265            }
266    
267            messages.add(de.getMessageObject());
268          }
269        }
270    
271        return configChangeResult;
272      }
273    
274    
275      /**
276       * Creates a workflow, registers the workflow with the server
277       * and registers the workflow with the default network group.
278       *
279       * @param workflowCfg  the workflow configuration
280       *
281       * @throws DirectoryException If a problem occurs while trying to
282       *                            decode a provided string as a DN or if
283       *                            the workflow ID for a provided workflow
284       *                            conflicts with the workflow ID of an existing
285       *                            workflow during workflow registration.
286       */
287      private void createAndRegisterWorkflow(
288          WorkflowCfg workflowCfg
289          ) throws DirectoryException
290      {
291        // The ID of the workflow to create
292        String workflowId = workflowCfg.getWorkflowId();
293    
294        // Create the root workflow element to associate with the workflow
295        String rootWorkflowElementID = workflowCfg.getWorkflowElement();
296        WorkflowElement rootWorkflowElement =
297          WorkflowElement.getWorkflowElement(rootWorkflowElementID);
298    
299        // Get the base DN targeted by the workflow
300        DN baseDN = workflowCfg.getBaseDN();
301    
302        // Create the workflow and register it with the server
303        WorkflowImpl workflowImpl =
304          new WorkflowImpl(workflowId, baseDN, rootWorkflowElement);
305        workflows.put(workflowCfg.dn(), workflowImpl);
306        workflowImpl.register();
307    
308        // Register the workflow with the default network group
309        NetworkGroup.getDefaultNetworkGroup().registerWorkflow(workflowImpl);
310      }
311    
312    }
313