/*
* 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 2009 Sun Microsystems, Inc.
* Portions Copyright 2012 ForgeRock AS
*/
package org.opends.server.workflowelement.externalchangelog;
import static org.opends.server.loggers.debug.DebugLogger.getTracer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.opends.server.admin.std.server.WorkflowElementCfg;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.PersistentSearch;
import org.opends.server.core.SearchOperation;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.replication.server.ReplicationServer;
import org.opends.server.types.CanceledOperationException;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Operation;
import org.opends.server.workflowelement.LeafWorkflowElement;
/**
* This class defines a workflow element for the external changelog (ECL);
* e-g an entity that handles the processing of an operation against the ECL.
*/
public class ECLWorkflowElement extends
LeafWorkflowElement<WorkflowElementCfg>
{
/**
* The tracer object for the debug logger.
*/
private static final DebugTracer TRACER = getTracer();
/**
*The set of persistent searches registered with this work flow element.
*/
private final List<PersistentSearch> persistentSearches =
new CopyOnWriteArrayList<PersistentSearch>();
/**
* A string indicating the type of the workflow element.
*/
public static final String ECL_WORKFLOW_ELEMENT = "EXTERNAL CHANGE LOG";
/**
* The replication server object to which we will submits request
* on the ECL. Retrieved from the local DirectoryServer.
*/
private ReplicationServer replicationServer;
/**
* Creates a new instance of the External Change Log workflow element.
* @param rs the provided replication server
* @throws DirectoryException If the ECL workflow is already registered.
*/
public ECLWorkflowElement(ReplicationServer rs)
throws DirectoryException
{
this.replicationServer =rs;
super.initialize(ECL_WORKFLOW_ELEMENT, ECL_WORKFLOW_ELEMENT);
super.setPrivate(true);
DirectoryServer.registerWorkflowElement(this);
}
/**
* {@inheritDoc}
*/
@Override
public void finalizeWorkflowElement()
{
// null all fields so that any use of the finalized object will raise
// an NPE
super.initialize(ECL_WORKFLOW_ELEMENT, null);
// Cancel all persistent searches.
for (PersistentSearch psearch : persistentSearches) {
psearch.cancel();
}
persistentSearches.clear();
}
/**
* {@inheritDoc}
*/
public void execute(Operation operation) throws CanceledOperationException {
switch (operation.getOperationType())
{
case SEARCH:
ECLSearchOperation searchOperation =
new ECLSearchOperation((SearchOperation) operation);
searchOperation.processECLSearch(this);
break;
case ABANDON:
// There is no processing for an abandon operation.
break;
case BIND:
case ADD:
case DELETE:
case MODIFY:
case MODIFY_DN:
case COMPARE:
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 <O> subtype of Operation
* @param <L> 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 <O extends Operation,L> void
attachLocalOperation (O globalOperation, L currentLocalOperation)
{
List<?> existingAttachment =
(List<?>) globalOperation.getAttachment(Operation.LOCALBACKENDOPERATIONS);
List<L> newAttachment = new ArrayList<L>();
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<L>) existingAttachment);
}
newAttachment.add (currentLocalOperation);
globalOperation.setAttachment(Operation.LOCALBACKENDOPERATIONS,
newAttachment);
}
/**
* Registers the provided persistent search operation with this
* workflow element so that it will be notified of any
* add, delete, modify, or modify DN operations that are performed.
*
* @param persistentSearch
* The persistent search operation to register with this
* workflow element.
*/
void registerPersistentSearch(PersistentSearch persistentSearch)
{
PersistentSearch.CancellationCallback callback =
new PersistentSearch.CancellationCallback()
{
public void persistentSearchCancelled(PersistentSearch psearch)
{
psearch.getSearchOperation().cancel(null);
persistentSearches.remove(psearch);
}
};
persistentSearches.add(persistentSearch);
persistentSearch.registerCancellationCallback(callback);
}
/**
* Gets the list of persistent searches currently active against
* this workflow element.
*
* @return The list of persistent searches currently active against
* this workflow element.
*/
public List<PersistentSearch> getPersistentSearches()
{
return persistentSearches;
}
/**
* Returns the associated replication server.
* @return the rs.
*/
public ReplicationServer getReplicationServer()
{
return this.replicationServer;
}
}