/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008 Sun Microsystems, Inc. */ package org.opends.server.workflowelement.localbackend; import java.util.ArrayList; import java.util.List; import java.util.TreeMap; import org.opends.messages.Message; import org.opends.server.admin.server.ConfigurationChangeListener; import org.opends.server.admin.server.ServerManagementContext; import org.opends.server.admin.std.server.BackendCfg; import org.opends.server.admin.std.server.LocalBackendWorkflowElementCfg; import org.opends.server.admin.std.server.RootCfg; import org.opends.server.api.Backend; import org.opends.server.config.ConfigException; import org.opends.server.core.AddOperation; import org.opends.server.core.BindOperation; import org.opends.server.core.CompareOperation; import org.opends.server.core.DeleteOperation; import org.opends.server.core.DirectoryServer; import org.opends.server.core.ModifyDNOperation; import org.opends.server.core.ModifyOperation; import org.opends.server.core.SearchOperation; import org.opends.server.types.*; import org.opends.server.workflowelement.LeafWorkflowElement; import static org.opends.server.config.ConfigConstants.*; /** * This class defines a local backend workflow element; e-g an entity that * handle the processing of an operation against a local backend. */ public class LocalBackendWorkflowElement extends LeafWorkflowElement implements ConfigurationChangeListener { // the backend associated with the local workflow element private Backend backend; // the set of local backend workflow elements registered with the server private static TreeMap registeredLocalBackends = new TreeMap(); // a lock to guarantee safe concurrent access to the registeredLocalBackends // variable private static Object registeredLocalBackendsLock = new Object(); // A string indicating the type of the workflow element. private final String BACKEND_WORKFLOW_ELEMENT = "Backend"; /** * Creates a new instance of the local backend workflow element. */ public LocalBackendWorkflowElement() { // There is nothing to do in this constructor. } /** * Initializes a new instance of the local backend workflow element. * This method is intended to be called by DirectoryServer when * workflow configuration mode is auto as opposed to * initializeWorkflowElement which is invoked when workflow * configuration mode is manual. * * @param workflowElementID the workflow element identifier * @param backend the backend associated to that workflow element */ private void initialize(String workflowElementID, Backend backend) { // Initialize the workflow ID super.initialize(workflowElementID, BACKEND_WORKFLOW_ELEMENT); this.backend = backend; if (this.backend != null) { setPrivate(this.backend.isPrivateBackend()); } } /** * Initializes a new instance of the local backend workflow element. * This method is intended to be called by DirectoryServer when * workflow configuration mode is manual as opposed to * initialize(String,Backend) which is invoked when workflow * configuration mode is auto. * * @param configuration The configuration for this local backend * workflow element. * * @throws ConfigException If there is a problem with the provided * configuration. * * @throws InitializationException If an error occurs while trying * to initialize this workflow * element that is not related to * the provided configuration. */ public void initializeWorkflowElement( LocalBackendWorkflowElementCfg configuration ) throws ConfigException, InitializationException { configuration.addLocalBackendChangeListener(this); // Read configuration and apply changes. processWorkflowElementConfig(configuration, true); } /** * {@inheritDoc} */ public void finalizeWorkflowElement() { // null all fields so that any use of the finalized object will raise // an NPE super.initialize(null, null); backend = null; } /** * {@inheritDoc} */ public boolean isConfigurationChangeAcceptable( LocalBackendWorkflowElementCfg configuration, List unacceptableReasons ) { boolean isAcceptable = processWorkflowElementConfig(configuration, false); return isAcceptable; } /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationChange( LocalBackendWorkflowElementCfg configuration ) { // Returned result. ConfigChangeResult changeResult = new ConfigChangeResult( ResultCode.SUCCESS, false, new ArrayList() ); processWorkflowElementConfig(configuration, true); return changeResult; } /** * Parses the provided configuration and configure the workflow element. * * @param configuration The new configuration containing the changes. * @param applyChanges If true then take into account the new configuration. * * @return true if the configuration is acceptable. */ private boolean processWorkflowElementConfig( LocalBackendWorkflowElementCfg configuration, boolean applyChanges ) { // returned status boolean isAcceptable = true; // If the workflow element is disabled then do nothing. Note that the // configuration manager could have finalized the object right before. if (configuration.isEnabled()) { // Read configuration. String newBackendID = configuration.getBackend(); Backend newBackend = DirectoryServer.getBackend(newBackendID); // If the backend is null (i.e. not found in the list of // registered backends, this is probably because we are looking // for the config backend if (newBackend == null) { ServerManagementContext context = ServerManagementContext.getInstance(); RootCfg root = context.getRootConfiguration(); try { BackendCfg backendCfg = root.getBackend(newBackendID); if (backendCfg.getBaseDN().contains(DN.decode(DN_CONFIG_ROOT))) { newBackend = DirectoryServer.getConfigHandler(); } } catch (Exception ex) { // Unable to find the backend newBackend = null; } } // Get the new configuration if (applyChanges) { super.initialize( configuration.getWorkflowElementId(), BACKEND_WORKFLOW_ELEMENT); backend = newBackend; if (backend != null) { setPrivate(backend.isPrivateBackend()); } } } return isAcceptable; } /** * Creates and registers a local backend with the server. * * @param workflowElementID the identifier of the workflow element to create * @param backend the backend to associate with the local backend * workflow element * * @return the existing local backend workflow element if it was * already created or a newly created local backend workflow * element. */ public static LocalBackendWorkflowElement createAndRegister( String workflowElementID, Backend backend) { LocalBackendWorkflowElement localBackend = null; // If the requested workflow element does not exist then create one. localBackend = registeredLocalBackends.get(workflowElementID); if (localBackend == null) { localBackend = new LocalBackendWorkflowElement(); localBackend.initialize(workflowElementID, backend); // store the new local backend in the list of registered backends registerLocalBackend(localBackend); } return localBackend; } /** * Removes a local backend that was registered with the server. * * @param workflowElementID the identifier of the workflow element to remove */ public static void remove(String workflowElementID) { deregisterLocalBackend(workflowElementID); } /** * Removes all the local backends that were registered with the server. * This function is intended to be called when the server is shutting down. */ public static void removeAll() { synchronized (registeredLocalBackendsLock) { for (LocalBackendWorkflowElement localBackend: registeredLocalBackends.values()) { deregisterLocalBackend(localBackend.getWorkflowElementID()); } } } /** * Registers a local backend with the server. * * @param localBackend the local backend to register with the server */ private static void registerLocalBackend( LocalBackendWorkflowElement localBackend) { synchronized (registeredLocalBackendsLock) { String localBackendID = localBackend.getWorkflowElementID(); LocalBackendWorkflowElement existingLocalBackend = registeredLocalBackends.get(localBackendID); if (existingLocalBackend == null) { TreeMap newLocalBackends = new TreeMap (registeredLocalBackends); newLocalBackends.put(localBackendID, localBackend); registeredLocalBackends = newLocalBackends; } } } /** * Deregisters a local backend with the server. * * @param workflowElementID the identifier of the workflow element to remove */ private static void deregisterLocalBackend(String workflowElementID) { synchronized (registeredLocalBackendsLock) { LocalBackendWorkflowElement existingLocalBackend = registeredLocalBackends.get(workflowElementID); if (existingLocalBackend != null) { TreeMap newLocalBackends = new TreeMap( registeredLocalBackends); newLocalBackends.remove(workflowElementID); registeredLocalBackends = newLocalBackends; } } } /** * {@inheritDoc} */ public void execute(Operation operation) throws CanceledOperationException { switch (operation.getOperationType()) { case BIND: LocalBackendBindOperation bindOperation = new LocalBackendBindOperation((BindOperation) operation); bindOperation.processLocalBind(backend); break; case SEARCH: LocalBackendSearchOperation searchOperation = new LocalBackendSearchOperation((SearchOperation) operation); searchOperation.processLocalSearch(backend); break; case ADD: LocalBackendAddOperation addOperation = new LocalBackendAddOperation((AddOperation) operation); addOperation.processLocalAdd(backend); break; case DELETE: LocalBackendDeleteOperation deleteOperation = new LocalBackendDeleteOperation((DeleteOperation) operation); deleteOperation.processLocalDelete(backend); break; case MODIFY: LocalBackendModifyOperation modifyOperation = new LocalBackendModifyOperation((ModifyOperation) operation); modifyOperation.processLocalModify(backend); break; case MODIFY_DN: LocalBackendModifyDNOperation modifyDNOperation = new LocalBackendModifyDNOperation((ModifyDNOperation) operation); modifyDNOperation.processLocalModifyDN(backend); break; case COMPARE: LocalBackendCompareOperation compareOperation = new LocalBackendCompareOperation((CompareOperation) operation); compareOperation.processLocalCompare(backend); break; case ABANDON: // There is no processing for an abandon operation. break; default: throw new AssertionError("Attempted to execute an invalid operation " + "type: " + operation.getOperationType() + " (" + operation + ")"); } } /** * Attaches the current local operation to the global operation so that * operation runner can execute local operation post response later on. * * @param subtype of Operation * @param subtype of LocalBackendOperation * @param globalOperation the global operation to which local operation * should be attached to * @param currentLocalOperation the local operation to attach to the global * operation */ @SuppressWarnings("unchecked") public static final void attachLocalOperation (O globalOperation, L currentLocalOperation) { List existingAttachment = (List) globalOperation.getAttachment(Operation.LOCALBACKENDOPERATIONS); List newAttachment = new ArrayList(); if (existingAttachment != null) { // This line raises an unchecked conversion warning. // There is nothing we can do to prevent this warning // so let's get rid of it since we know the cast is safe. newAttachment.addAll ((List) existingAttachment); } newAttachment.add (currentLocalOperation); globalOperation.setAttachment(Operation.LOCALBACKENDOPERATIONS, newAttachment); } }