opends/src/server/org/opends/server/api/ClientConnection.java
@@ -32,6 +32,7 @@ import java.nio.ByteBuffer; import java.nio.channels.Selector; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -45,7 +46,6 @@ import org.opends.server.core.SearchOperation; import org.opends.server.core.networkgroups.NetworkGroup; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.AbstractOperation; import org.opends.server.types.Attribute; import org.opends.server.types.AttributeType; import org.opends.server.types.AttributeValue; @@ -814,8 +814,7 @@ * @return The set of operations in progress for this client * connection. */ public abstract Collection<AbstractOperation> getOperationsInProgress(); public abstract Collection<Operation> getOperationsInProgress(); @@ -828,8 +827,7 @@ * @return The operation in progress with the specified message ID, * or {@code null} if no such operation could be found. */ public abstract AbstractOperation getOperationInProgress(int messageID); public abstract Operation getOperationInProgress(int messageID); @@ -857,8 +855,7 @@ * @return The set of persistent searches registered for this * client. */ public final CopyOnWriteArrayList<PersistentSearch> getPersistentSearches() public final List<PersistentSearch> getPersistentSearches() { return persistentSearches; } @@ -1660,13 +1657,13 @@ if ((authzDN == null) || authzDN.isNullDN()) { return java.util.Collections.<Group>emptySet(); return Collections.<Group>emptySet(); } Entry userEntry = DirectoryServer.getEntry(authzDN); if (userEntry == null) { return java.util.Collections.<Group>emptySet(); return Collections.<Group>emptySet(); } HashSet<Group> groupSet = new HashSet<Group>(); opends/src/server/org/opends/server/core/AbandonOperationBasis.java
@@ -39,8 +39,6 @@ import org.opends.server.api.ClientConnection; import org.opends.server.api.plugin.PluginResult; import org.opends.server.loggers.debug.DebugLogger; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.*; import org.opends.server.types.operation.PostOperationAbandonOperation; import org.opends.server.types.operation.PreParseAbandonOperation; @@ -57,11 +55,6 @@ PostOperationAbandonOperation { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = DebugLogger.getTracer(); // The message ID of the operation that should be abandoned. private final int idToAbandon; @@ -251,7 +244,7 @@ // code to reflect whether the abandon was successful and an error message // if it was not. Even though there is no response, the result should // still be logged. AbstractOperation operation = Operation operation = clientConnection.getOperationInProgress(idToAbandon); if (operation == null) { opends/src/server/org/opends/server/core/AddOperationBasis.java
@@ -25,7 +25,6 @@ * Copyright 2007-2008 Sun Microsystems, Inc. */ package org.opends.server.core; import org.opends.messages.Message; import org.opends.messages.MessageBuilder; @@ -38,10 +37,8 @@ import static org.opends.server.core.CoreConstants.LOG_ELEMENT_RESULT_CODE; import static org.opends.server.loggers.AccessLogger.logAddRequest; import static org.opends.server.loggers.AccessLogger.logAddResponse; import static org.opends.server.loggers.ErrorLogger.logError; import static org.opends.server.loggers.debug.DebugLogger.debugEnabled; import static org.opends.messages.CoreMessages.*; import static org.opends.server.util.StaticUtils.getExceptionMessage; import static org.opends.server.util.StaticUtils.toLowerCase; import java.util.ArrayList; @@ -797,9 +794,10 @@ // Log the add response message. logAddResponse(this); // Notifies any persistent searches that might be registered with the // server. notifyPersistentSearches(workflowExecuted); // Invoke the post-response callbacks. if (workflowExecuted) { invokePostResponseCallbacks(); } // Invoke the post-response add plugins. invokePostResponsePlugins(workflowExecuted); @@ -855,60 +853,6 @@ } /** * Notifies any persistent searches that might be registered with the server. * If no workflow has been executed then don't notify persistent searches. * * @param workflowExecuted <code>true</code> if a workflow has been * executed */ private void notifyPersistentSearches(boolean workflowExecuted) { if (! workflowExecuted) { return; } List<?> localOperations = (List<?>)getAttachment(Operation.LOCALBACKENDOPERATIONS); if (localOperations != null) { for (Object localOp : localOperations) { LocalBackendAddOperation localOperation = (LocalBackendAddOperation)localOp; if ((getResultCode() == ResultCode.SUCCESS) && (localOperation.getEntryToAdd() != null)) { for (PersistentSearch persistentSearch : DirectoryServer.getPersistentSearches()) { try { persistentSearch.processAdd(localOperation, localOperation.getEntryToAdd()); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } Message message = ERR_ADD_ERROR_NOTIFYING_PERSISTENT_SEARCH.get( String.valueOf(persistentSearch), getExceptionMessage(e)); logError(message); DirectoryServer.deregisterPersistentSearch(persistentSearch); } } } } } } /** * Updates the error message and the result code of the operation. opends/src/server/org/opends/server/core/DeleteOperationBasis.java
@@ -25,7 +25,6 @@ * Copyright 2007-2008 Sun Microsystems, Inc. */ package org.opends.server.core; import org.opends.messages.Message; import org.opends.messages.MessageBuilder; @@ -37,11 +36,8 @@ import static org.opends.server.core.CoreConstants.LOG_ELEMENT_RESULT_CODE; import static org.opends.server.loggers.AccessLogger.logDeleteRequest; import static org.opends.server.loggers.AccessLogger.logDeleteResponse; import static org.opends.server.loggers.ErrorLogger.logError; import static org.opends.server.loggers.debug.DebugLogger.debugEnabled; import static org.opends.messages.CoreMessages.*; import static org.opends.server.util.StaticUtils.getExceptionMessage; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -452,9 +448,10 @@ // Log the delete response. logDeleteResponse(this); // Notifies any persistent searches that might be registered with the // server. notifyPersistentSearches(workflowExecuted); // Invoke the post-response callbacks. if (workflowExecuted) { invokePostResponseCallbacks(); } // Invoke the post-response delete plugins. invokePostResponsePlugins(workflowExecuted); @@ -511,61 +508,6 @@ /** * Notifies any persistent searches that might be registered with the server. * If no workflow has been executed then don't notify persistent searches. * * @param workflowExecuted <code>true</code> if a workflow has been * executed */ private void notifyPersistentSearches(boolean workflowExecuted) { if (! workflowExecuted) { return; } List localOperations = (List)getAttachment(Operation.LOCALBACKENDOPERATIONS); if (localOperations != null) { for (Object localOp : localOperations) { LocalBackendDeleteOperation localOperation = (LocalBackendDeleteOperation)localOp; // Notify any persistent searches that might be registered with the // server. if (getResultCode() == ResultCode.SUCCESS) { for (PersistentSearch persistentSearch : DirectoryServer.getPersistentSearches()) { try { persistentSearch.processDelete(localOperation, localOperation.getEntryToDelete()); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } Message message = ERR_DELETE_ERROR_NOTIFYING_PERSISTENT_SEARCH. get(String.valueOf(persistentSearch), getExceptionMessage(e)); logError(message); DirectoryServer.deregisterPersistentSearch(persistentSearch); } } } } } } /** * Updates the error message and the result code of the operation. * * This method is called because no workflows were found to process opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -497,9 +497,6 @@ // The set of import task listeners registered with the Directory Server. private CopyOnWriteArrayList<ImportTaskListener> importTaskListeners; // The set of persistent searches registered with the Directory Server. private CopyOnWriteArrayList<PersistentSearch> persistentSearches; // The set of restore task listeners registered with the Directory Server. private CopyOnWriteArrayList<RestoreTaskListener> restoreTaskListeners; @@ -937,8 +934,6 @@ directoryServer.baseDnRegistry = new BaseDnRegistry(); directoryServer.changeNotificationListeners = new CopyOnWriteArrayList<ChangeNotificationListener>(); directoryServer.persistentSearches = new CopyOnWriteArrayList<PersistentSearch>(); directoryServer.shutdownListeners = new CopyOnWriteArrayList<ServerShutdownListener>(); directoryServer.synchronizationProviders = @@ -7730,56 +7725,6 @@ /** * Retrieves the set of persistent searches registered with the Directory * Server. * * @return The set of persistent searches registered with the Directory * Server. */ public static CopyOnWriteArrayList<PersistentSearch> getPersistentSearches() { return directoryServer.persistentSearches; } /** * Registers the provided persistent search operation with the Directory * Server 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 * the Directory Server. */ public static void registerPersistentSearch(PersistentSearch persistentSearch) { directoryServer.persistentSearches.add(persistentSearch); persistentSearch.getSearchOperation().getClientConnection(). registerPersistentSearch(persistentSearch); } /** * Deregisters the provided persistent search operation with the Directory * Server so that it will no longer be notified of any add, delete, modify, or * modify DN operations that are performed. * * @param persistentSearch The persistent search operation to deregister * with the Directory Server. */ public static void deregisterPersistentSearch(PersistentSearch persistentSearch) { directoryServer.persistentSearches.remove(persistentSearch); persistentSearch.getSearchOperation().getClientConnection(). deregisterPersistentSearch(persistentSearch); } /** * Retrieves the set of synchronization providers that have been registered * with the Directory Server. * opends/src/server/org/opends/server/core/ModifyDNOperationBasis.java
@@ -25,7 +25,6 @@ * Copyright 2006-2008 Sun Microsystems, Inc. */ package org.opends.server.core; import org.opends.messages.Message; import org.opends.messages.MessageBuilder; import java.util.ArrayList; @@ -47,9 +46,7 @@ import org.opends.server.loggers.debug.DebugLogger; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.loggers.ErrorLogger; import static org.opends.messages.CoreMessages.*; import static org.opends.server.util.StaticUtils.*; /** @@ -665,9 +662,10 @@ // Log the modify DN response. logModifyDNResponse(this); // Notifies any persistent searches that might be registered with the // server. notifyPersistentSearches(workflowExecuted); // Invoke the post-response callbacks. if (workflowExecuted) { invokePostResponseCallbacks(); } // Invoke the post-response modify DN plugins. invokePostResponsePlugins(workflowExecuted); @@ -724,63 +722,6 @@ /** * Notifies any persistent searches that might be registered with the server. * If no workflow has been executed then don't notify persistent searches. * * @param workflowExecuted <code>true</code> if a workflow has been * executed */ private void notifyPersistentSearches(boolean workflowExecuted) { if (! workflowExecuted) { return; } List localOperations = (List)getAttachment(Operation.LOCALBACKENDOPERATIONS); if (localOperations != null) { for (Object localOperation : localOperations) { LocalBackendModifyDNOperation localOp = (LocalBackendModifyDNOperation)localOperation; // Notify any persistent searches that might be registered with // the server. if (getResultCode() == ResultCode.SUCCESS) { for (PersistentSearch persistentSearch : DirectoryServer.getPersistentSearches()) { try { persistentSearch.processModifyDN( localOp, localOp.getOriginalEntry(), localOp.getUpdatedEntry()); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } Message message = ERR_MODDN_ERROR_NOTIFYING_PERSISTENT_SEARCH.get( String.valueOf(persistentSearch), getExceptionMessage(e)); ErrorLogger.logError(message); DirectoryServer.deregisterPersistentSearch(persistentSearch); } } } } } } /** * Updates the error message and the result code of the operation. * * This method is called because no workflows were found to process opends/src/server/org/opends/server/core/ModifyOperationBasis.java
@@ -27,9 +27,6 @@ package org.opends.server.core; import org.opends.messages.MessageBuilder; import org.opends.messages.Message; import static org.opends.server.core.CoreConstants.LOG_ELEMENT_ENTRY_DN; import static org.opends.server.core.CoreConstants.LOG_ELEMENT_ERROR_MESSAGE; import static org.opends.server.core.CoreConstants.LOG_ELEMENT_MATCHED_DN; @@ -38,11 +35,8 @@ import static org.opends.server.core.CoreConstants.LOG_ELEMENT_RESULT_CODE; import static org.opends.server.loggers.AccessLogger.logModifyRequest; import static org.opends.server.loggers.AccessLogger.logModifyResponse; import static org.opends.server.loggers.ErrorLogger.logError; import static org.opends.server.loggers.debug.DebugLogger.debugEnabled; import static org.opends.messages.CoreMessages.*; import static org.opends.server.util.StaticUtils.getExceptionMessage; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -554,9 +548,10 @@ // Log the modify response. logModifyResponse(this); // Notifies any persistent searches that might be registered with the // server. notifyPersistentSearches(workflowExecuted); // Invoke the post-response callbacks. if (workflowExecuted) { invokePostResponseCallbacks(); } // Invoke the post-response add plugins. invokePostResponsePlugins(workflowExecuted); @@ -612,61 +607,6 @@ } /** * Notifies any persistent searches that might be registered with the server. * If no workflow has been executed then don't notify persistent searches. * * @param workflowExecuted <code>true</code> if a workflow has been * executed */ private void notifyPersistentSearches(boolean workflowExecuted) { if (! workflowExecuted) { return; } List localOperations = (List)getAttachment(Operation.LOCALBACKENDOPERATIONS); if (localOperations != null) { for (Object localOp : localOperations) { LocalBackendModifyOperation localOperation = (LocalBackendModifyOperation)localOp; // Notify any persistent searches that might be registered with // the server. if (localOperation.getResultCode() == ResultCode.SUCCESS) { for (PersistentSearch persistentSearch : DirectoryServer.getPersistentSearches()) { try { persistentSearch.processModify(localOperation, localOperation.getCurrentEntry(), localOperation.getModifiedEntry()); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } Message message = ERR_MODIFY_ERROR_NOTIFYING_PERSISTENT_SEARCH. get(String.valueOf(persistentSearch), getExceptionMessage(e)); logError(message); DirectoryServer.deregisterPersistentSearch(persistentSearch); } } } } } } /** * Updates the error message and the result code of the operation. opends/src/server/org/opends/server/core/OperationWrapper.java
@@ -484,5 +484,13 @@ throws CanceledOperationException { operation.checkIfCanceled(signalTooLate); } /** * {@inheritDoc} */ public void registerPostResponseCallback(Runnable callback) { operation.registerPostResponseCallback(callback); } } opends/src/server/org/opends/server/core/PersistentSearch.java
@@ -27,206 +27,219 @@ package org.opends.server.core; import static org.opends.server.loggers.debug.DebugLogger.*; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import org.opends.server.controls.EntryChangeNotificationControl; import org.opends.server.controls.PersistentSearchChangeType; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.CancelResult; import org.opends.server.types.Control; import org.opends.server.types.DN; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.DirectoryException; import org.opends.server.types.Entry; import org.opends.server.types.ResultCode; import org.opends.server.types.SearchFilter; import org.opends.server.types.SearchScope; import org.opends.server.workflowelement.localbackend.*; import static org.opends.server.loggers.debug.DebugLogger.*; import org.opends.server.loggers.debug.DebugTracer; /** * This class defines a data structure that will be used to hold the information * necessary for processing a persistent search. * This class defines a data structure that will be used to hold the * information necessary for processing a persistent search. */ public class PersistentSearch public final class PersistentSearch { /** * A cancellation call-back which can be used by work-flow element * implementations in order to register for resource cleanup when a * persistent search is cancelled. */ public static interface CancellationCallback { /** * The provided persistent search has been cancelled. Any * resources associated with the persistent search should be * released. * * @param psearch * The persistent search which has just been cancelled. */ void persistentSearchCancelled(PersistentSearch psearch); } /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); // Indicates whether entries returned should include the entry change // notification control. private boolean returnECs; // Indicates whether entries returned should include the entry // change notification control. private final boolean returnECs; // The base DN for the search operation. private DN baseDN; private final DN baseDN; // The set of change types we want to see. private Set<PersistentSearchChangeType> changeTypes; private final Set<PersistentSearchChangeType> changeTypes; // The scope for the search operation. private SearchScope scope; private final SearchScope scope; // The filter for the search operation. private SearchFilter filter; private final SearchFilter filter; // The reference to the associated search operation. private SearchOperation searchOperation; private final SearchOperation searchOperation; // Indicates whether or not this persistent search has already been // aborted. private boolean isCancelled = false; // Cancellation callbacks which should be run when this persistent // search is cancelled. private final List<CancellationCallback> cancellationCallbacks = new CopyOnWriteArrayList<CancellationCallback>(); /** * Creates a new persistent search object with the provided information. * Creates a new persistent search object with the provided * information. * * @param searchOperation The search operation for this persistent search. * @param changeTypes The change types for which changes should be * examined. * @param returnECs Indicates whether to include entry change * notification controls in search result entries * sent to the client. * @param searchOperation * The search operation for this persistent search. * @param changeTypes * The change types for which changes should be examined. * @param returnECs * Indicates whether to include entry change notification * controls in search result entries sent to the client. */ public PersistentSearch(SearchOperation searchOperation, Set<PersistentSearchChangeType> changeTypes, boolean returnECs) Set<PersistentSearchChangeType> changeTypes, boolean returnECs) { this.searchOperation = searchOperation; this.changeTypes = changeTypes; this.returnECs = returnECs; this.changeTypes = changeTypes; this.returnECs = returnECs; baseDN = searchOperation.getBaseDN(); scope = searchOperation.getScope(); filter = searchOperation.getFilter(); this.baseDN = searchOperation.getBaseDN(); this.scope = searchOperation.getScope(); this.filter = searchOperation.getFilter(); } /** * Retrieves the search operation for this persistent search. * Cancels this persistent search operation. On exit this persistent * search will no longer be valid and any resources associated with * it will have been released. * * @return The search operation for this persistent search. * @return The result of the cancellation. */ public SearchOperation getSearchOperation() public synchronized CancelResult cancel() { return searchOperation; if (!isCancelled) { isCancelled = true; // The persistent search can no longer be cancelled. searchOperation.getClientConnection().deregisterPersistentSearch(this); // Notify any cancellation callbacks. for (CancellationCallback callback : cancellationCallbacks) { try { callback.persistentSearchCancelled(this); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } } } } return new CancelResult(ResultCode.CANCELED, null); } /** * Retrieves the set of change types for this persistent search. * Gets the message ID associated with this persistent search. * * @return The set of change types for this persistent search. * @return The message ID associated with this persistent search. */ public Set<PersistentSearchChangeType> getChangeTypes() public int getMessageID() { return changeTypes; return searchOperation.getMessageID(); } /** * Retrieves the returnECs flag for this persistent search. * Notifies the persistent searches that an entry has been added. * * @return The return ECs flag for this persistent search. * @param entry * The entry that was added. * @param changeNumber * The change number associated with the operation that * added the entry, or {@code -1} if there is no change * number. */ public boolean getReturnECs() { return returnECs; } /** * Retrieves the base DN for this persistent search. * * @return The base DN for this persistent search. */ public DN getBaseDN() { return baseDN; } /** * Retrieves the scope for this persistent search. * * @return The scope for this persistent search. */ public SearchScope getScope() { return scope; } /** * Retrieves the filter for this persistent search. * * @return The filter for this persistent search. */ public SearchFilter getFilter() { return filter; } /** * Performs any necessary processing for the provided add operation. * * @param addOperation The add operation that has been processed. * @param entry The entry that was added. */ public void processAdd(LocalBackendAddOperation addOperation, Entry entry) public void processAdd(Entry entry, long changeNumber) { // See if we care about add operations. if (! changeTypes.contains(PersistentSearchChangeType.ADD)) if (!changeTypes.contains(PersistentSearchChangeType.ADD)) { return; } // Make sure that the entry is within our target scope. switch (scope) { case BASE_OBJECT: if (! baseDN.equals(entry.getDN())) { return; } break; case SINGLE_LEVEL: if (! baseDN.equals(entry.getDN().getParentDNInSuffix())) { return; } break; case WHOLE_SUBTREE: if (! baseDN.isAncestorOf(entry.getDN())) { return; } break; case SUBORDINATE_SUBTREE: if (baseDN.equals(entry.getDN()) || (! baseDN.isAncestorOf(entry.getDN()))) { return; } break; default: case BASE_OBJECT: if (!baseDN.equals(entry.getDN())) { return; } break; case SINGLE_LEVEL: if (!baseDN.equals(entry.getDN().getParentDNInSuffix())) { return; } break; case WHOLE_SUBTREE: if (!baseDN.isAncestorOf(entry.getDN())) { return; } break; case SUBORDINATE_SUBTREE: if (baseDN.equals(entry.getDN()) || (!baseDN.isAncestorOf(entry.getDN()))) { return; } break; default: return; } // Make sure that the entry matches the target filter. try { if (! filter.matchesEntry(entry)) if (!filter.matchesEntry(entry)) { return; } @@ -243,25 +256,22 @@ return; } // The entry is one that should be sent to the client. See if we also need // to construct an entry change notification control. // The entry is one that should be sent to the client. See if we // also need to construct an entry change notification control. ArrayList<Control> entryControls = new ArrayList<Control>(1); if (returnECs) { entryControls.add(new EntryChangeNotificationControl( PersistentSearchChangeType.ADD, addOperation.getChangeNumber())); PersistentSearchChangeType.ADD, changeNumber)); } // Send the entry and see if we should continue processing. If not, then // deregister this persistent search. // Send the entry and see if we should continue processing. If // not, then deregister this persistent search. try { if (! searchOperation.returnEntry(entry, entryControls)) if (!searchOperation.returnEntry(entry, entryControls)) { DirectoryServer.deregisterPersistentSearch(this); cancel(); searchOperation.sendSearchResultDone(); } } @@ -272,7 +282,7 @@ TRACER.debugCaught(DebugLogLevel.ERROR, e); } DirectoryServer.deregisterPersistentSearch(this); cancel(); try { @@ -291,58 +301,58 @@ /** * Performs any necessary processing for the provided delete operation. * Notifies the persistent searches that an entry has been deleted. * * @param deleteOperation The delete operation that has been processed. * @param entry The entry that was removed. * @param entry * The entry that was deleted. * @param changeNumber * The change number associated with the operation that * deleted the entry, or {@code -1} if there is no change * number. */ public void processDelete(LocalBackendDeleteOperation deleteOperation, Entry entry) public void processDelete(Entry entry, long changeNumber) { // See if we care about delete operations. if (! changeTypes.contains(PersistentSearchChangeType.DELETE)) if (!changeTypes.contains(PersistentSearchChangeType.DELETE)) { return; } // Make sure that the entry is within our target scope. switch (scope) { case BASE_OBJECT: if (! baseDN.equals(entry.getDN())) { return; } break; case SINGLE_LEVEL: if (! baseDN.equals(entry.getDN().getParentDNInSuffix())) { return; } break; case WHOLE_SUBTREE: if (! baseDN.isAncestorOf(entry.getDN())) { return; } break; case SUBORDINATE_SUBTREE: if (baseDN.equals(entry.getDN()) || (! baseDN.isAncestorOf(entry.getDN()))) { return; } break; default: case BASE_OBJECT: if (!baseDN.equals(entry.getDN())) { return; } break; case SINGLE_LEVEL: if (!baseDN.equals(entry.getDN().getParentDNInSuffix())) { return; } break; case WHOLE_SUBTREE: if (!baseDN.isAncestorOf(entry.getDN())) { return; } break; case SUBORDINATE_SUBTREE: if (baseDN.equals(entry.getDN()) || (!baseDN.isAncestorOf(entry.getDN()))) { return; } break; default: return; } // Make sure that the entry matches the target filter. try { if (! filter.matchesEntry(entry)) if (!filter.matchesEntry(entry)) { return; } @@ -359,25 +369,22 @@ return; } // The entry is one that should be sent to the client. See if we also need // to construct an entry change notification control. // The entry is one that should be sent to the client. See if we // also need to construct an entry change notification control. ArrayList<Control> entryControls = new ArrayList<Control>(1); if (returnECs) { entryControls.add(new EntryChangeNotificationControl( PersistentSearchChangeType.DELETE, deleteOperation.getChangeNumber())); PersistentSearchChangeType.DELETE, changeNumber)); } // Send the entry and see if we should continue processing. If not, then // deregister this persistent search. // Send the entry and see if we should continue processing. If // not, then deregister this persistent search. try { if (! searchOperation.returnEntry(entry, entryControls)) if (!searchOperation.returnEntry(entry, entryControls)) { DirectoryServer.deregisterPersistentSearch(this); cancel(); searchOperation.sendSearchResultDone(); } } @@ -388,7 +395,7 @@ TRACER.debugCaught(DebugLogLevel.ERROR, e); } DirectoryServer.deregisterPersistentSearch(this); cancel(); try { @@ -407,61 +414,78 @@ /** * Performs any necessary processing for the provided modify operation. * Notifies the persistent searches that an entry has been modified. * * @param modifyOperation The modify operation that has been processed. * @param oldEntry The entry before the modification was applied. * @param newEntry The entry after the modification was applied. * @param entry * The entry after it was modified. * @param changeNumber * The change number associated with the operation that * modified the entry, or {@code -1} if there is no change * number. */ public void processModify(LocalBackendModifyOperation modifyOperation, Entry oldEntry, Entry newEntry) public void processModify(Entry entry, long changeNumber) { processModify(entry, changeNumber, entry); } /** * Notifies persistent searches that an entry has been modified. * * @param entry * The entry after it was modified. * @param changeNumber * The change number associated with the operation that * modified the entry, or {@code -1} if there is no change * number. * @param oldEntry * The entry before it was modified. */ public void processModify(Entry entry, long changeNumber, Entry oldEntry) { // See if we care about modify operations. if (! changeTypes.contains(PersistentSearchChangeType.MODIFY)) if (!changeTypes.contains(PersistentSearchChangeType.MODIFY)) { return; } // Make sure that the entry is within our target scope. switch (scope) { case BASE_OBJECT: if (! baseDN.equals(oldEntry.getDN())) { return; } break; case SINGLE_LEVEL: if (! baseDN.equals(oldEntry.getDN().getParentDNInSuffix())) { return; } break; case WHOLE_SUBTREE: if (! baseDN.isAncestorOf(oldEntry.getDN())) { return; } break; case SUBORDINATE_SUBTREE: if (baseDN.equals(oldEntry.getDN()) || (! baseDN.isAncestorOf(oldEntry.getDN()))) { return; } break; default: case BASE_OBJECT: if (!baseDN.equals(oldEntry.getDN())) { return; } break; case SINGLE_LEVEL: if (!baseDN.equals(oldEntry.getDN().getParent())) { return; } break; case WHOLE_SUBTREE: if (!baseDN.isAncestorOf(oldEntry.getDN())) { return; } break; case SUBORDINATE_SUBTREE: if (baseDN.equals(oldEntry.getDN()) || (!baseDN.isAncestorOf(oldEntry.getDN()))) { return; } break; default: return; } // Make sure that the entry matches the target filter. try { if ((! filter.matchesEntry(oldEntry)) && (! filter.matchesEntry(newEntry))) if ((!filter.matchesEntry(oldEntry)) && (!filter.matchesEntry(entry))) { return; } @@ -478,25 +502,22 @@ return; } // The entry is one that should be sent to the client. See if we also need // to construct an entry change notification control. // The entry is one that should be sent to the client. See if we // also need to construct an entry change notification control. ArrayList<Control> entryControls = new ArrayList<Control>(1); if (returnECs) { entryControls.add(new EntryChangeNotificationControl( PersistentSearchChangeType.MODIFY, modifyOperation.getChangeNumber())); PersistentSearchChangeType.MODIFY, changeNumber)); } // Send the entry and see if we should continue processing. If not, then // deregister this persistent search. // Send the entry and see if we should continue processing. If // not, then deregister this persistent search. try { if (! searchOperation.returnEntry(newEntry, entryControls)) if (!searchOperation.returnEntry(entry, entryControls)) { DirectoryServer.deregisterPersistentSearch(this); cancel(); searchOperation.sendSearchResultDone(); } } @@ -507,7 +528,7 @@ TRACER.debugCaught(DebugLogLevel.ERROR, e); } DirectoryServer.deregisterPersistentSearch(this); cancel(); try { @@ -526,82 +547,83 @@ /** * Performs any necessary processing for the provided modify DN operation. * Notifies the persistent searches that an entry has been renamed. * * @param modifyDNOperation The modify DN operation that has been processed. * @param oldEntry The entry before the modify DN. * @param newEntry The entry after the modify DN. * @param entry * The entry after it was modified. * @param changeNumber * The change number associated with the operation that * modified the entry, or {@code -1} if there is no change * number. * @param oldDN * The DN of the entry before it was renamed. */ public void processModifyDN(LocalBackendModifyDNOperation modifyDNOperation, Entry oldEntry, Entry newEntry) public void processModifyDN(Entry entry, long changeNumber, DN oldDN) { // See if we care about modify DN operations. if (! changeTypes.contains(PersistentSearchChangeType.MODIFY_DN)) if (!changeTypes.contains(PersistentSearchChangeType.MODIFY_DN)) { return; } // Make sure that the old or new entry is within our target scope. In this // case, we need to check the DNs of both the old and new entry so we know // which one(s) should be compared against the filter. // Make sure that the old or new entry is within our target scope. // In this case, we need to check the DNs of both the old and new // entry so we know which one(s) should be compared against the // filter. boolean oldMatches = false; boolean newMatches = false; switch (scope) { case BASE_OBJECT: oldMatches = baseDN.equals(oldEntry.getDN()); newMatches = baseDN.equals(newEntry.getDN()); case BASE_OBJECT: oldMatches = baseDN.equals(oldDN); newMatches = baseDN.equals(entry.getDN()); if (! (oldMatches || newMatches)) { return; } break; case SINGLE_LEVEL: oldMatches = baseDN.equals(oldEntry.getDN().getParentDNInSuffix()); newMatches = baseDN.equals(newEntry.getDN().getParentDNInSuffix()); if (! (oldMatches || newMatches)) { return; } break; case WHOLE_SUBTREE: oldMatches = baseDN.isAncestorOf(oldEntry.getDN()); newMatches = baseDN.isAncestorOf(newEntry.getDN()); if (! (oldMatches || newMatches)) { return; } break; case SUBORDINATE_SUBTREE: oldMatches = ((! baseDN.equals(oldEntry.getDN())) && baseDN.isAncestorOf(oldEntry.getDN())); newMatches = ((! baseDN.equals(newEntry.getDN())) && baseDN.isAncestorOf(newEntry.getDN())); if (! (oldMatches || newMatches)) { return; } break; default: if (!(oldMatches || newMatches)) { return; } } break; case SINGLE_LEVEL: oldMatches = baseDN.equals(oldDN.getParent()); newMatches = baseDN.equals(entry.getDN().getParent()); if (!(oldMatches || newMatches)) { return; } break; case WHOLE_SUBTREE: oldMatches = baseDN.isAncestorOf(oldDN); newMatches = baseDN.isAncestorOf(entry.getDN()); if (!(oldMatches || newMatches)) { return; } break; case SUBORDINATE_SUBTREE: oldMatches = ((!baseDN.equals(oldDN)) && baseDN.isAncestorOf(oldDN)); newMatches = ((!baseDN.equals(entry.getDN())) && baseDN .isAncestorOf(entry.getDN())); if (!(oldMatches || newMatches)) { return; } break; default: return; } // Make sure that the entry matches the target filter. try { if (((! oldMatches) || (! filter.matchesEntry(oldEntry))) && ((! newMatches) && (! filter.matchesEntry(newEntry)))) if (!oldMatches && !newMatches && !filter.matchesEntry(entry)) { return; } @@ -618,26 +640,22 @@ return; } // The entry is one that should be sent to the client. See if we also need // to construct an entry change notification control. // The entry is one that should be sent to the client. See if we // also need to construct an entry change notification control. ArrayList<Control> entryControls = new ArrayList<Control>(1); if (returnECs) { entryControls.add(new EntryChangeNotificationControl( PersistentSearchChangeType.MODIFY_DN, oldEntry.getDN(), modifyDNOperation.getChangeNumber())); PersistentSearchChangeType.MODIFY_DN, oldDN, changeNumber)); } // Send the entry and see if we should continue processing. If not, then // deregister this persistent search. // Send the entry and see if we should continue processing. If // not, then deregister this persistent search. try { if (! searchOperation.returnEntry(newEntry, entryControls)) if (!searchOperation.returnEntry(entry, entryControls)) { DirectoryServer.deregisterPersistentSearch(this); cancel(); searchOperation.sendSearchResultDone(); } } @@ -648,7 +666,7 @@ TRACER.debugCaught(DebugLogLevel.ERROR, e); } DirectoryServer.deregisterPersistentSearch(this); cancel(); try { @@ -667,10 +685,26 @@ /** * Registers a cancellation callback with this persistent search. * The cancellation callback will be notified when this persistent * search has been cancelled. * * @param callback * The cancellation callback. */ public void registerCancellationCallback(CancellationCallback callback) { cancellationCallbacks.add(callback); } /** * Retrieves a string representation of this persistent search. * * @return A string representation of this persistent search. * @return A string representation of this persistent search. */ @Override public String toString() { StringBuilder buffer = new StringBuilder(); @@ -681,10 +715,11 @@ /** * Appends a string representation of this persistent search to the provided * buffer. * Appends a string representation of this persistent search to the * provided buffer. * * @param buffer The buffer to which the information should be appended. * @param buffer * The buffer to which the information should be appended. */ public void toString(StringBuilder buffer) { @@ -701,4 +736,3 @@ buffer.append("\")"); } } opends/src/server/org/opends/server/core/SearchOperationBasis.java
@@ -1277,7 +1277,7 @@ if (persistentSearch != null) { DirectoryServer.deregisterPersistentSearch(persistentSearch); persistentSearch.cancel(); persistentSearch = null; } } opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java
@@ -141,7 +141,7 @@ private AuthenticationInfo authenticationInfo; // The empty operation list for this connection. private LinkedList<AbstractOperation> operationList; private LinkedList<Operation> operationList; // The connection ID for this client connection. private long connectionID; @@ -258,7 +258,7 @@ } connectionID = nextConnectionID.getAndDecrement(); operationList = new LinkedList<AbstractOperation>(); operationList = new LinkedList<Operation>(); try { @@ -298,7 +298,7 @@ super.setLookthroughLimit(0); connectionID = nextConnectionID.getAndDecrement(); operationList = new LinkedList<AbstractOperation>(); operationList = new LinkedList<Operation>(); try { @@ -2919,7 +2919,7 @@ mayExtend=false, mayInvoke=false) @Override() public Collection<AbstractOperation> getOperationsInProgress() public Collection<Operation> getOperationsInProgress() { return operationList; } opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java
@@ -100,7 +100,7 @@ private ConnectionSecurityProvider securityProvider; // The empty operation list for this connection. private LinkedList<AbstractOperation> operationList; private LinkedList<Operation> operationList; // The connection ID for this client connection. private long connectionID; @@ -155,7 +155,7 @@ true, ERR_LDAP_CONNHANDLER_REJECTED_BY_SERVER.get()); } operationList = new LinkedList<AbstractOperation>(); operationList = new LinkedList<Operation>(); try { @@ -1130,7 +1130,7 @@ * * @return The set of operations in progress for this client connection. */ public Collection<AbstractOperation> getOperationsInProgress() public Collection<Operation> getOperationsInProgress() { return operationList; } opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
@@ -138,7 +138,7 @@ private byte[] elementValue; // The set of all operations currently in progress on this connection. private ConcurrentHashMap<Integer,AbstractOperation> operationsInProgress; private ConcurrentHashMap<Integer,Operation> operationsInProgress; // The number of operations performed on this connection. // Used to compare with the resource limits of the network group. @@ -264,7 +264,7 @@ nextOperationID = new AtomicLong(0); connectionValid = true; disconnectRequested = false; operationsInProgress = new ConcurrentHashMap<Integer,AbstractOperation>(); operationsInProgress = new ConcurrentHashMap<Integer,Operation>(); operationsPerformed = 0; operationsPerformedLock = new Object(); keepStats = connectionHandler.keepStats(); @@ -1136,7 +1136,7 @@ * * @return The set of operations in progress for this client connection. */ public Collection<AbstractOperation> getOperationsInProgress() public Collection<Operation> getOperationsInProgress() { return operationsInProgress.values(); } @@ -1151,7 +1151,7 @@ * @return The operation in progress with the specified message ID, or * <CODE>null</CODE> if no such operation could be found. */ public AbstractOperation getOperationInProgress(int messageID) public Operation getOperationInProgress(int messageID) { return operationsInProgress.get(messageID); } @@ -1192,7 +1192,7 @@ // See if there is already an operation in progress with the same // message ID. If so, then we can't allow it. AbstractOperation op = operationsInProgress.get(messageID); Operation op = operationsInProgress.get(messageID); if (op != null) { Message message = @@ -1252,7 +1252,7 @@ */ public boolean removeOperationInProgress(int messageID) { AbstractOperation operation = operationsInProgress.remove(messageID); Operation operation = operationsInProgress.remove(messageID); if (operation == null) { return false; @@ -1279,16 +1279,15 @@ public CancelResult cancelOperation(int messageID, CancelRequest cancelRequest) { AbstractOperation op = operationsInProgress.get(messageID); Operation op = operationsInProgress.get(messageID); if (op == null) { // See if the operation is in the list of persistent searches. for (PersistentSearch ps : getPersistentSearches()) { if (ps.getSearchOperation().getMessageID() == messageID) if (ps.getMessageID() == messageID) { CancelResult cancelResult = ps.getSearchOperation().cancel(cancelRequest); CancelResult cancelResult = ps.cancel(); if (keepStats && (cancelResult.getResultCode() == ResultCode.CANCELED)) @@ -1329,11 +1328,11 @@ { try { for (AbstractOperation o : operationsInProgress.values()) for (Operation o : operationsInProgress.values()) { try { o.abort(cancelRequest); o.abort(cancelRequest); // TODO: Assume its cancelled? if (keepStats) @@ -1361,7 +1360,7 @@ for (PersistentSearch persistentSearch : getPersistentSearches()) { DirectoryServer.deregisterPersistentSearch(persistentSearch); persistentSearch.cancel(); } } catch (Exception e) @@ -1400,7 +1399,7 @@ continue; } AbstractOperation o = operationsInProgress.get(msgID); Operation o = operationsInProgress.get(msgID); if (o != null) { try @@ -1429,7 +1428,7 @@ for (PersistentSearch persistentSearch : getPersistentSearches()) { DirectoryServer.deregisterPersistentSearch(persistentSearch); persistentSearch.cancel(); lastCompletionTime.set(TimeThread.getTime()); } } opends/src/server/org/opends/server/types/AbstractOperation.java
@@ -33,12 +33,14 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.opends.server.api.ClientConnection; import org.opends.server.types.operation.PostResponseOperation; import org.opends.server.types.operation.PreParseOperation; import org.opends.server.core.DirectoryServer; import static org.opends.server.loggers.debug. DebugLogger.debugEnabled; import static org.opends.server.loggers.debug.DebugLogger.getTracer; @@ -168,6 +170,9 @@ // nanoseconds. private long processingStopNanoTime; // The callbacks to be invoked once a response has been sent. private List<Runnable> postResponseCallbacks = null; /** * Creates a new operation with the provided information. * @@ -1148,5 +1153,47 @@ * processing. */ public abstract void run(); /** * {@inheritDoc} */ public final void registerPostResponseCallback(Runnable callback) { if (postResponseCallbacks == null) { postResponseCallbacks = new LinkedList<Runnable>(); } postResponseCallbacks.add(callback); } /** * Invokes the post response callbacks that were registered with * this operation. */ protected final void invokePostResponseCallbacks() { if (postResponseCallbacks != null) { for (Runnable callback : postResponseCallbacks) { try { callback.run(); } catch (Exception e) { // Should not happen. if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } } } } } } opends/src/server/org/opends/server/types/Operation.java
@@ -622,5 +622,15 @@ public void checkIfCanceled(boolean signalTooLate) throws CanceledOperationException; /** * Registers a callback which should be run once this operation has * completed and the response sent back to the client. * * @param callback * The callback to be run once this operation has completed * and the response sent back to the client. */ public void registerPostResponseCallback(Runnable callback); } opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
@@ -65,6 +65,7 @@ import org.opends.server.core.AddOperationWrapper; import org.opends.server.core.DirectoryServer; import org.opends.server.core.PasswordPolicy; import org.opends.server.core.PersistentSearch; import org.opends.server.core.PluginConfigManager; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.schema.AuthPasswordSyntax; @@ -173,16 +174,17 @@ /** * Process this add operation against a local backend. * * @param backend The backend in which the add operation should be * processed. * * @throws CanceledOperationException if this operation should be * cancelled * @param wfe * The local backend work-flow element. * @throws CanceledOperationException * if this operation should be cancelled */ void processLocalAdd(Backend backend) throws CanceledOperationException { void processLocalAdd(final LocalBackendWorkflowElement wfe) throws CanceledOperationException { boolean executePostOpPlugins = false; this.backend = backend; this.backend = wfe.getBackend(); ClientConnection clientConnection = getClientConnection(); // Get the plugin config manager that will be used for invoking plugins. @@ -772,29 +774,41 @@ } } // Notify any change notification listeners that might be registered with // the server. if ((getResultCode() == ResultCode.SUCCESS) && (entry != null)) // Register a post-response call-back which will notify persistent // searches and change listeners. if (getResultCode() == ResultCode.SUCCESS) { for (ChangeNotificationListener changeListener : DirectoryServer.getChangeNotificationListeners()) registerPostResponseCallback(new Runnable() { try public void run() { changeListener.handleAddOperation(this, entry); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); // Notify persistent searches. for (PersistentSearch psearch : wfe.getPersistentSearches()) { psearch.processAdd(entry, getChangeNumber()); } logError(ERR_ADD_ERROR_NOTIFYING_CHANGE_LISTENER.get( getExceptionMessage(e))); // Notify change listeners. for (ChangeNotificationListener changeListener : DirectoryServer .getChangeNotificationListeners()) { try { changeListener.handleAddOperation(LocalBackendAddOperation.this, entry); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } logError(ERR_ADD_ERROR_NOTIFYING_CHANGE_LISTENER .get(getExceptionMessage(e))); } } } } }); } } opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java
@@ -178,12 +178,13 @@ /** * Process this bind operation in a local backend. * * @param backend The backend in which the bind operation should be * processed. * @param wfe * The local backend work-flow element. * */ void processLocalBind(Backend backend) void processLocalBind(LocalBackendWorkflowElement wfe) { this.backend = backend; this.backend = wfe.getBackend(); // Initialize a number of variables for use during the bind processing. clientConnection = getClientConnection(); opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java
@@ -116,16 +116,17 @@ /** * Process this compare operation in a local backend. * * @param backend The backend in which the compare operation should be * processed. * * @throws CanceledOperationException if this operation should be * cancelled * @param wfe * The local backend work-flow element. * @throws CanceledOperationException * if this operation should be cancelled */ void processLocalCompare(Backend backend) throws CanceledOperationException { void processLocalCompare(LocalBackendWorkflowElement wfe) throws CanceledOperationException { boolean executePostOpPlugins = false; this.backend = backend; this.backend = wfe.getBackend(); clientConnection = getClientConnection(); opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
@@ -47,6 +47,7 @@ import org.opends.server.core.DeleteOperationWrapper; import org.opends.server.core.DeleteOperation; import org.opends.server.core.DirectoryServer; import org.opends.server.core.PersistentSearch; import org.opends.server.core.PluginConfigManager; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.AttributeType; @@ -143,16 +144,16 @@ /** * Process this delete operation in a local backend. * * @param backend The backend in which the delete operation should be * processed. * * @throws CanceledOperationException if this operation should be * cancelled * @param wfe * The local backend work-flow element. * @throws CanceledOperationException * if this operation should be cancelled */ void processLocalDelete(Backend backend) throws CanceledOperationException { void processLocalDelete(final LocalBackendWorkflowElement wfe) throws CanceledOperationException { boolean executePostOpPlugins = false; this.backend = backend; this.backend = wfe.getBackend(); clientConnection = getClientConnection(); @@ -444,29 +445,43 @@ } // Notify any change notification listeners that might be registered with // the server. // Register a post-response call-back which will notify persistent // searches and change listeners. if (getResultCode() == ResultCode.SUCCESS) { for (ChangeNotificationListener changeListener : DirectoryServer.getChangeNotificationListeners()) registerPostResponseCallback(new Runnable() { try public void run() { changeListener.handleDeleteOperation(this, entry); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); // Notify persistent searches. for (PersistentSearch psearch : wfe.getPersistentSearches()) { psearch.processDelete(entry, getChangeNumber()); } Message message = ERR_DELETE_ERROR_NOTIFYING_CHANGE_LISTENER.get( getExceptionMessage(e)); logError(message); // Notify change listeners. for (ChangeNotificationListener changeListener : DirectoryServer .getChangeNotificationListeners()) { try { changeListener.handleDeleteOperation( LocalBackendDeleteOperation.this, entry); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } Message message = ERR_DELETE_ERROR_NOTIFYING_CHANGE_LISTENER .get(getExceptionMessage(e)); logError(message); } } } } }); } } opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
@@ -51,6 +51,7 @@ import org.opends.server.core.DirectoryServer; import org.opends.server.core.ModifyDNOperation; import org.opends.server.core.ModifyDNOperationWrapper; import org.opends.server.core.PersistentSearch; import org.opends.server.core.PluginConfigManager; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.Attribute; @@ -180,16 +181,16 @@ /** * Process this modify DN operation in a local backend. * * @param backend The backend in which the modify DN operation should be * processed. * * @throws CanceledOperationException if this operation should be * cancelled * @param wfe * The local backend work-flow element. * @throws CanceledOperationException * if this operation should be cancelled */ void processLocalModifyDN(Backend backend) throws CanceledOperationException { void processLocalModifyDN(final LocalBackendWorkflowElement wfe) throws CanceledOperationException { boolean executePostOpPlugins = false; this.backend = backend; this.backend = wfe.getBackend(); clientConnection = getClientConnection(); @@ -632,30 +633,45 @@ } } // Notify any change notification listeners that might be registered with // the server. // Register a post-response call-back which will notify persistent // searches and change listeners. if (getResultCode() == ResultCode.SUCCESS) { for (ChangeNotificationListener changeListener : DirectoryServer.getChangeNotificationListeners()) registerPostResponseCallback(new Runnable() { try public void run() { changeListener.handleModifyDNOperation(this, currentEntry, newEntry); } catch (Exception e) { if (debugEnabled()) // Notify persistent searches. for (PersistentSearch psearch : wfe.getPersistentSearches()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); psearch.processModifyDN(newEntry, getChangeNumber(), currentEntry.getDN()); } Message message = ERR_MODDN_ERROR_NOTIFYING_CHANGE_LISTENER.get( getExceptionMessage(e)); logError(message); // Notify change listeners. for (ChangeNotificationListener changeListener : DirectoryServer .getChangeNotificationListeners()) { try { changeListener.handleModifyDNOperation( LocalBackendModifyDNOperation.this, currentEntry, newEntry); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } Message message = ERR_MODDN_ERROR_NOTIFYING_CHANGE_LISTENER .get(getExceptionMessage(e)); logError(message); } } } } }); } } opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
@@ -65,6 +65,7 @@ import org.opends.server.core.ModifyOperation; import org.opends.server.core.ModifyOperationWrapper; import org.opends.server.core.PasswordPolicyState; import org.opends.server.core.PersistentSearch; import org.opends.server.core.PluginConfigManager; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.protocols.asn1.ASN1OctetString; @@ -293,16 +294,16 @@ /** * Process this modify operation against a local backend. * * @param backend The backend in which the modify operation should be * performed. * * @throws CanceledOperationException if this operation should be * cancelled * @param wfe * The local backend work-flow element. * @throws CanceledOperationException * if this operation should be cancelled */ void processLocalModify(Backend backend) throws CanceledOperationException { void processLocalModify(final LocalBackendWorkflowElement wfe) throws CanceledOperationException { boolean executePostOpPlugins = false; this.backend = backend; this.backend = wfe.getBackend(); clientConnection = getClientConnection(); @@ -690,11 +691,46 @@ } // Notify any change notification listeners that might be registered with // the server. // Register a post-response call-back which will notify persistent // searches and change listeners. if (getResultCode() == ResultCode.SUCCESS) { notifyChangeListeners(); registerPostResponseCallback(new Runnable() { public void run() { // Notify persistent searches. for (PersistentSearch psearch : wfe.getPersistentSearches()) { psearch.processModify(modifiedEntry, getChangeNumber(), currentEntry); } // Notify change listeners. for (ChangeNotificationListener changeListener : DirectoryServer .getChangeNotificationListeners()) { try { changeListener .handleModifyOperation(LocalBackendModifyOperation.this, currentEntry, modifiedEntry); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } Message message = ERR_MODIFY_ERROR_NOTIFYING_CHANGE_LISTENER .get(getExceptionMessage(e)); logError(message); } } } }); } } @@ -2228,32 +2264,6 @@ /** * Notify any registered change listeners about this update. */ private void notifyChangeListeners() { for (ChangeNotificationListener changeListener : DirectoryServer.getChangeNotificationListeners()) { try { changeListener.handleModifyOperation(this, currentEntry, modifiedEntry); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } Message message = ERR_MODIFY_ERROR_NOTIFYING_CHANGE_LISTENER.get( getExceptionMessage(e)); logError(message); } } } private boolean handleConflictResolution() { boolean returnVal = true; opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java
@@ -121,16 +121,16 @@ /** * Process this search operation against a local backend. * * @param backend The backend in which the search operation should be * performed. * * @throws CanceledOperationException if this operation should be * cancelled * @param wfe * The local backend work-flow element. * @throws CanceledOperationException * if this operation should be cancelled */ void processLocalSearch(Backend backend) throws CanceledOperationException { void processLocalSearch(LocalBackendWorkflowElement wfe) throws CanceledOperationException { boolean executePostOpPlugins = false; this.backend = backend; this.backend = wfe.getBackend(); clientConnection = getClientConnection(); @@ -230,7 +230,8 @@ // If there's a persistent search, then register it with the server. if (persistentSearch != null) { DirectoryServer.registerPersistentSearch(persistentSearch); wfe.registerPersistentSearch(persistentSearch); clientConnection.registerPersistentSearch(persistentSearch); setSendResponse(false); } @@ -254,7 +255,7 @@ if (persistentSearch != null) { DirectoryServer.deregisterPersistentSearch(persistentSearch); persistentSearch.cancel(); setSendResponse(true); } @@ -264,7 +265,7 @@ { if (persistentSearch != null) { DirectoryServer.deregisterPersistentSearch(persistentSearch); persistentSearch.cancel(); setSendResponse(true); } @@ -283,7 +284,7 @@ if (persistentSearch != null) { DirectoryServer.deregisterPersistentSearch(persistentSearch); persistentSearch.cancel(); setSendResponse(true); } opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
@@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.List; import java.util.TreeMap; import java.util.concurrent.CopyOnWriteArrayList; import org.opends.messages.Message; import org.opends.server.admin.server.ConfigurationChangeListener; @@ -47,6 +48,7 @@ import org.opends.server.core.DirectoryServer; import org.opends.server.core.ModifyDNOperation; import org.opends.server.core.ModifyOperation; import org.opends.server.core.PersistentSearch; import org.opends.server.core.SearchOperation; import org.opends.server.types.*; import org.opends.server.workflowelement.LeafWorkflowElement; @@ -73,6 +75,10 @@ registeredLocalBackends = new TreeMap<String, LocalBackendWorkflowElement>(); // The set of persistent searches registered with this work flow // element. private final List<PersistentSearch> persistentSearches = new CopyOnWriteArrayList<PersistentSearch>(); // a lock to guarantee safe concurrent access to the registeredLocalBackends // variable @@ -154,6 +160,12 @@ // an NPE super.initialize(null, null); backend = null; // Cancel all persistent searches. for (PersistentSearch psearch : persistentSearches) { psearch.cancel(); } persistentSearches.clear(); } @@ -372,43 +384,43 @@ case BIND: LocalBackendBindOperation bindOperation = new LocalBackendBindOperation((BindOperation) operation); bindOperation.processLocalBind(backend); bindOperation.processLocalBind(this); break; case SEARCH: LocalBackendSearchOperation searchOperation = new LocalBackendSearchOperation((SearchOperation) operation); searchOperation.processLocalSearch(backend); searchOperation.processLocalSearch(this); break; case ADD: LocalBackendAddOperation addOperation = new LocalBackendAddOperation((AddOperation) operation); addOperation.processLocalAdd(backend); addOperation.processLocalAdd(this); break; case DELETE: LocalBackendDeleteOperation deleteOperation = new LocalBackendDeleteOperation((DeleteOperation) operation); deleteOperation.processLocalDelete(backend); deleteOperation.processLocalDelete(this); break; case MODIFY: LocalBackendModifyOperation modifyOperation = new LocalBackendModifyOperation((ModifyOperation) operation); modifyOperation.processLocalModify(backend); modifyOperation.processLocalModify(this); break; case MODIFY_DN: LocalBackendModifyDNOperation modifyDNOperation = new LocalBackendModifyDNOperation((ModifyDNOperation) operation); modifyDNOperation.processLocalModifyDN(backend); modifyDNOperation.processLocalModifyDN(this); break; case COMPARE: LocalBackendCompareOperation compareOperation = new LocalBackendCompareOperation((CompareOperation) operation); compareOperation.processLocalCompare(backend); compareOperation.processLocalCompare(this); break; case ABANDON: @@ -456,5 +468,58 @@ newAttachment); } /** * Gets the backend associated with this local backend workflow * element. * * @return The backend associated with this local backend workflow * element. */ Backend getBackend() { return backend; } /** * Registers the provided persistent search operation with this * local backend 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 * local backend workflow element. */ void registerPersistentSearch(PersistentSearch persistentSearch) { PersistentSearch.CancellationCallback callback = new PersistentSearch.CancellationCallback() { public void persistentSearchCancelled(PersistentSearch psearch) { persistentSearches.remove(psearch); } }; persistentSearches.add(persistentSearch); persistentSearch.registerCancellationCallback(callback); } /** * Gets the list of persistent searches currently active against * this local backend workflow element. * * @return The list of persistent searches currently active against * this local backend workflow element. */ List<PersistentSearch> getPersistentSearches() { return persistentSearches; } } opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java
@@ -54,7 +54,6 @@ import org.opends.server.protocols.ldap.LDAPAttribute; import org.opends.server.protocols.ldap.LDAPFilter; import org.opends.server.protocols.ldap.LDAPModification; import org.opends.server.types.AbstractOperation; import org.opends.server.types.Attributes; import org.opends.server.types.AuthenticationInfo; import org.opends.server.types.CancelRequest; @@ -65,6 +64,7 @@ import org.opends.server.types.Entry; import org.opends.server.types.Modification; import org.opends.server.types.ModificationType; import org.opends.server.types.Operation; import org.opends.server.types.RawAttribute; import org.opends.server.types.RawModification; import org.opends.server.types.RDN; @@ -1074,7 +1074,7 @@ { InternalClientConnection conn = InternalClientConnection.getRootConnection(); Collection<AbstractOperation> opList = conn.getOperationsInProgress(); Collection<Operation> opList = conn.getOperationsInProgress(); assertNotNull(opList); assertTrue(opList.isEmpty()); }