/*
|
* 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-2010 Sun Microsystems, Inc.
|
*/
|
package org.opends.server.core;
|
|
|
|
import java.util.*;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|
import org.opends.server.api.Backend;
|
import org.opends.server.api.BackendInitializationListener;
|
import org.opends.server.api.SubentryChangeListener;
|
import org.opends.server.api.plugin.InternalDirectoryServerPlugin;
|
import org.opends.server.api.plugin.PluginResult;
|
import org.opends.server.api.plugin.PluginResult.PostOperation;
|
import org.opends.server.api.plugin.PluginResult.PreOperation;
|
import org.opends.server.api.plugin.PluginType;
|
import org.opends.server.controls.SubentriesControl;
|
import org.opends.server.loggers.debug.DebugTracer;
|
import org.opends.server.protocols.internal.InternalClientConnection;
|
import org.opends.server.protocols.internal.InternalSearchOperation;
|
import org.opends.server.types.Control;
|
import org.opends.server.types.DebugLogLevel;
|
import org.opends.server.types.DereferencePolicy;
|
import org.opends.server.types.DN;
|
import org.opends.server.types.DirectoryException;
|
import org.opends.server.types.Entry;
|
import org.opends.server.types.SearchResultEntry;
|
import org.opends.server.types.SearchScope;
|
import org.opends.server.types.SearchFilter;
|
import org.opends.server.types.SubEntry;
|
import org.opends.server.types.operation.PostOperationAddOperation;
|
import org.opends.server.types.operation.PostOperationDeleteOperation;
|
import org.opends.server.types.operation.PostOperationModifyDNOperation;
|
import org.opends.server.types.operation.PostOperationModifyOperation;
|
import org.opends.server.types.operation.PreOperationAddOperation;
|
import org.opends.server.types.operation.PreOperationDeleteOperation;
|
import org.opends.server.types.operation.PreOperationModifyDNOperation;
|
import org.opends.server.types.operation.PreOperationModifyOperation;
|
import org.opends.server.workflowelement.localbackend.
|
LocalBackendSearchOperation;
|
|
import static org.opends.messages.CoreMessages.*;
|
import static org.opends.server.loggers.debug.DebugLogger.*;
|
import static org.opends.server.loggers.ErrorLogger.*;
|
import static org.opends.server.util.ServerConstants.*;
|
import static org.opends.server.config.ConfigConstants.*;
|
|
|
|
/**
|
* This class provides a mechanism for interacting with subentries defined in
|
* the Directory Server. It will handle all necessary processing at server
|
* startup to identify and load subentries within the server.
|
* <BR><BR>
|
* FIXME: At the present time, it assumes that all of the necessary
|
* information about subentries defined in the server can be held in
|
* memory. If it is determined that this approach is not workable
|
* in all cases, then we will need an alternate strategy.
|
*/
|
public class SubentryManager extends InternalDirectoryServerPlugin
|
implements BackendInitializationListener
|
{
|
/**
|
* The tracer object for the debug logger.
|
*/
|
private static final DebugTracer TRACER = getTracer();
|
|
// A mapping between the DNs and applicable subentries.
|
private HashMap<DN,List<SubEntry>> dn2SubEntry;
|
|
// A mapping between the DNs and applicable collective subentries.
|
private HashMap<DN,List<SubEntry>> dn2CollectiveSubEntry;
|
|
// Internal search all operational attributes.
|
private LinkedHashSet<String> requestAttrs;
|
|
// Lock to protect internal data structures.
|
private final ReentrantReadWriteLock lock;
|
|
// The set of change notification listeners.
|
private CopyOnWriteArrayList<SubentryChangeListener>
|
changeListeners;
|
|
// Dummy configuration DN for Subentry Manager.
|
private static final String CONFIG_DN = "cn=Subentry Manager,cn=config";
|
|
/**
|
* Creates a new instance of this subentry manager.
|
*
|
* @throws DirectoryException If a problem occurs while
|
* creating an instance of
|
* the subentry manager.
|
*/
|
public SubentryManager() throws DirectoryException
|
{
|
super(DN.decode(CONFIG_DN), EnumSet.of(
|
PluginType.PRE_OPERATION_ADD,
|
PluginType.PRE_OPERATION_DELETE,
|
PluginType.PRE_OPERATION_MODIFY,
|
PluginType.PRE_OPERATION_MODIFY_DN,
|
PluginType.POST_OPERATION_ADD,
|
PluginType.POST_OPERATION_DELETE,
|
PluginType.POST_OPERATION_MODIFY,
|
PluginType.POST_OPERATION_MODIFY_DN),
|
true);
|
|
lock = new ReentrantReadWriteLock();
|
|
dn2SubEntry = new HashMap<DN,List<SubEntry>>();
|
dn2CollectiveSubEntry = new HashMap<DN,List<SubEntry>>();
|
|
changeListeners =
|
new CopyOnWriteArrayList<SubentryChangeListener>();
|
|
requestAttrs = new LinkedHashSet<String>();
|
requestAttrs.add("*");
|
requestAttrs.add("+");
|
|
DirectoryServer.registerInternalPlugin(this);
|
DirectoryServer.registerBackendInitializationListener(this);
|
}
|
|
/**
|
* Perform any required finalization tasks for Subentry Manager.
|
* This should only be called at Directory Server shutdown.
|
*/
|
public void finalizeSubentryManager()
|
{
|
// Deregister as internal plugin and
|
// backend initialization listener.
|
DirectoryServer.deregisterInternalPlugin(this);
|
DirectoryServer.deregisterBackendInitializationListener(this);
|
}
|
|
/**
|
* Registers the provided change notification listener with this manager
|
* so that it will be notified of any add, delete, modify, or modify DN
|
* operations that are performed.
|
*
|
* @param changeListener The change notification listener to register
|
* with this manager.
|
*/
|
public void registerChangeListener(
|
SubentryChangeListener changeListener)
|
{
|
changeListeners.add(changeListener);
|
}
|
|
/**
|
* Deregisters the provided change notification listener with this manager
|
* so that it will no longer be notified of any add, delete, modify, or
|
* modify DN operations that are performed.
|
*
|
* @param changeListener The change notification listener to deregister
|
* with this manager.
|
*/
|
public void deregisterChangeListener(
|
SubentryChangeListener changeListener)
|
{
|
changeListeners.remove(changeListener);
|
}
|
|
/**
|
* Add a given entry to this subentry manager.
|
* @param entry to add.
|
*/
|
private void addSubEntry(Entry entry) throws DirectoryException
|
{
|
SubEntry subEntry = new SubEntry(entry);
|
RFC3672SubtreeSpecification subSpec =
|
subEntry.getSubTreeSpecification();
|
DN subDN = subSpec.getBaseDN();
|
List<SubEntry> subList = null;
|
lock.writeLock().lock();
|
try
|
{
|
if (subEntry.isCollective())
|
{
|
subList = dn2CollectiveSubEntry.get(subDN);
|
}
|
else
|
{
|
subList = dn2SubEntry.get(subDN);
|
}
|
if (subList == null)
|
{
|
subList = new ArrayList<SubEntry>();
|
if (subEntry.isCollective())
|
{
|
dn2CollectiveSubEntry.put(subDN, subList);
|
}
|
else
|
{
|
dn2SubEntry.put(subDN, subList);
|
}
|
}
|
subList.add(subEntry);
|
}
|
finally
|
{
|
lock.writeLock().unlock();
|
}
|
}
|
|
/**
|
* Remove a given entry from this subentry manager.
|
* @param entry to remove.
|
*/
|
private void removeSubEntry(Entry entry)
|
{
|
lock.writeLock().lock();
|
try
|
{
|
boolean removed = false;
|
Iterator<Map.Entry<DN, List<SubEntry>>> setIterator =
|
dn2SubEntry.entrySet().iterator();
|
while (setIterator.hasNext())
|
{
|
Map.Entry<DN, List<SubEntry>> mapEntry = setIterator.next();
|
List<SubEntry> subList = mapEntry.getValue();
|
Iterator<SubEntry> listIterator = subList.iterator();
|
while (listIterator.hasNext())
|
{
|
SubEntry subEntry = listIterator.next();
|
if (subEntry.getDN().equals(entry.getDN()))
|
{
|
listIterator.remove();
|
removed = true;
|
break;
|
}
|
}
|
if (subList.isEmpty())
|
{
|
setIterator.remove();
|
}
|
if (removed)
|
{
|
return;
|
}
|
}
|
setIterator = dn2CollectiveSubEntry.entrySet().iterator();
|
while (setIterator.hasNext())
|
{
|
Map.Entry<DN, List<SubEntry>> mapEntry = setIterator.next();
|
List<SubEntry> subList = mapEntry.getValue();
|
Iterator<SubEntry> listIterator = subList.iterator();
|
while (listIterator.hasNext())
|
{
|
SubEntry subEntry = listIterator.next();
|
if (subEntry.getDN().equals(entry.getDN()))
|
{
|
listIterator.remove();
|
removed = true;
|
break;
|
}
|
}
|
if (subList.isEmpty())
|
{
|
setIterator.remove();
|
}
|
if (removed)
|
{
|
return;
|
}
|
}
|
}
|
finally
|
{
|
lock.writeLock().unlock();
|
}
|
}
|
|
/**
|
* {@inheritDoc} In this case, the server will search the backend to find
|
* all subentries that it may contain and register them with this manager.
|
*/
|
public void performBackendInitializationProcessing(Backend backend)
|
{
|
InternalClientConnection conn =
|
InternalClientConnection.getRootConnection();
|
|
LinkedList<Control> requestControls = new LinkedList<Control>();
|
requestControls.add(new SubentriesControl(true, true));
|
|
SearchFilter filter = null;
|
try
|
{
|
filter = SearchFilter.createFilterFromString("(|" +
|
"(" + ATTR_OBJECTCLASS + "=" + OC_SUBENTRY + ")" +
|
"(" + ATTR_OBJECTCLASS + "=" + OC_LDAP_SUBENTRY + ")" +
|
")");
|
if (backend.getEntryCount() > 0 && ! backend.isIndexed(filter))
|
{
|
logError(WARN_SUBENTRY_FILTER_NOT_INDEXED.get(
|
String.valueOf(filter), backend.getBackendID()));
|
}
|
}
|
catch (Exception e)
|
{
|
if (debugEnabled())
|
{
|
TRACER.debugCaught(DebugLogLevel.ERROR, e);
|
}
|
}
|
|
for (DN baseDN : backend.getBaseDNs())
|
{
|
try
|
{
|
if (! backend.entryExists(baseDN))
|
{
|
continue;
|
}
|
}
|
catch (Exception e)
|
{
|
if (debugEnabled())
|
{
|
TRACER.debugCaught(DebugLogLevel.ERROR, e);
|
}
|
|
// FIXME -- Is there anything that we need to do here?
|
continue;
|
}
|
|
InternalSearchOperation internalSearch = new InternalSearchOperation(
|
conn, InternalClientConnection.nextOperationID(),
|
InternalClientConnection.nextMessageID(),
|
requestControls, baseDN, SearchScope.WHOLE_SUBTREE,
|
DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
|
filter, requestAttrs, null);
|
LocalBackendSearchOperation localSearch =
|
new LocalBackendSearchOperation(internalSearch);
|
|
try
|
{
|
backend.search(localSearch);
|
}
|
catch (Exception e)
|
{
|
if (debugEnabled())
|
{
|
TRACER.debugCaught(DebugLogLevel.ERROR, e);
|
}
|
|
// FIXME -- Is there anything that we need to do here?
|
continue;
|
}
|
|
for (SearchResultEntry entry : internalSearch.getSearchEntries())
|
{
|
if (entry.isSubentry() || entry.isLDAPSubentry())
|
{
|
try
|
{
|
addSubEntry(entry);
|
}
|
catch (Exception e)
|
{
|
if (debugEnabled())
|
{
|
TRACER.debugCaught(DebugLogLevel.ERROR, e);
|
}
|
|
// FIXME -- Handle this.
|
continue;
|
}
|
}
|
}
|
}
|
}
|
|
/**
|
* Return all subentries for this manager.
|
* Note that this getter will skip any collective subentries,
|
* returning only applicable regular subentries.
|
* @return all subentries for this manager.
|
*/
|
public List<SubEntry> getSubentries()
|
{
|
if (dn2SubEntry.isEmpty())
|
{
|
return Collections.emptyList();
|
}
|
|
List<SubEntry> subentries = new ArrayList<SubEntry>();
|
|
lock.readLock().lock();
|
try
|
{
|
for (List<SubEntry> subList : dn2SubEntry.values())
|
{
|
subentries.addAll(subList);
|
}
|
}
|
finally
|
{
|
lock.readLock().unlock();
|
}
|
|
return subentries;
|
}
|
|
/**
|
* Return subentries applicable to specific DN.
|
* Note that this getter will skip any collective subentries,
|
* returning only applicable regular subentries.
|
* @param dn for which to retrieve applicable
|
* subentries.
|
* @return applicable subentries.
|
*/
|
public List<SubEntry> getSubentries(DN dn)
|
{
|
if (dn2SubEntry.isEmpty())
|
{
|
return Collections.emptyList();
|
}
|
|
List<SubEntry> subentries = new ArrayList<SubEntry>();
|
|
lock.readLock().lock();
|
try
|
{
|
for (DN subDN = dn; subDN != null;
|
subDN = subDN.getParent())
|
{
|
List<SubEntry> subList = dn2SubEntry.get(subDN);
|
if (subList != null)
|
{
|
for (SubEntry subEntry : subList)
|
{
|
RFC3672SubtreeSpecification subSpec =
|
subEntry.getSubTreeSpecification();
|
if (subSpec.isDNWithinScope(dn))
|
{
|
subentries.add(subEntry);
|
}
|
}
|
}
|
}
|
}
|
finally
|
{
|
lock.readLock().unlock();
|
}
|
|
return subentries;
|
}
|
|
/**
|
* Return subentries applicable to specific entry.
|
* Note that this getter will skip any collective subentries,
|
* returning only applicable regular subentries.
|
* @param entry for which to retrieve applicable
|
* subentries.
|
* @return applicable subentries.
|
*/
|
public List<SubEntry> getSubentries(Entry entry)
|
{
|
if (dn2SubEntry.isEmpty())
|
{
|
return Collections.emptyList();
|
}
|
|
List<SubEntry> subentries = new ArrayList<SubEntry>();
|
|
lock.readLock().lock();
|
try
|
{
|
for (DN subDN = entry.getDN(); subDN != null;
|
subDN = subDN.getParent())
|
{
|
List<SubEntry> subList = dn2SubEntry.get(subDN);
|
if (subList != null)
|
{
|
for (SubEntry subEntry : subList)
|
{
|
RFC3672SubtreeSpecification subSpec =
|
subEntry.getSubTreeSpecification();
|
if (subSpec.isWithinScope(entry))
|
{
|
subentries.add(subEntry);
|
}
|
}
|
}
|
}
|
}
|
finally
|
{
|
lock.readLock().unlock();
|
}
|
|
return subentries;
|
}
|
|
/**
|
* Return collective subentries applicable to specific DN.
|
* Note that this getter will skip any regular subentries,
|
* returning only applicable collective subentries.
|
* @param dn for which to retrieve applicable
|
* subentries.
|
* @return applicable subentries.
|
*/
|
public List<SubEntry> getCollectiveSubentries(DN dn)
|
{
|
if (dn2CollectiveSubEntry.isEmpty())
|
{
|
return Collections.emptyList();
|
}
|
|
List<SubEntry> subentries = new ArrayList<SubEntry>();
|
|
lock.readLock().lock();
|
try
|
{
|
for (DN subDN = dn; subDN != null;
|
subDN = subDN.getParent())
|
{
|
List<SubEntry> subList = dn2CollectiveSubEntry.get(subDN);
|
if (subList != null)
|
{
|
for (SubEntry subEntry : subList)
|
{
|
RFC3672SubtreeSpecification subSpec =
|
subEntry.getSubTreeSpecification();
|
if (subSpec.isDNWithinScope(dn))
|
{
|
subentries.add(subEntry);
|
}
|
}
|
}
|
}
|
}
|
finally
|
{
|
lock.readLock().unlock();
|
}
|
|
return subentries;
|
}
|
|
/**
|
* Return collective subentries applicable to specific entry.
|
* Note that this getter will skip any regular subentries,
|
* returning only applicable collective subentries.
|
* @param entry for which to retrieve applicable
|
* subentries.
|
* @return applicable subentries.
|
*/
|
public List<SubEntry> getCollectiveSubentries(Entry entry)
|
{
|
if (dn2CollectiveSubEntry.isEmpty())
|
{
|
return Collections.emptyList();
|
}
|
|
List<SubEntry> subentries = new ArrayList<SubEntry>();
|
|
lock.readLock().lock();
|
try
|
{
|
for (DN subDN = entry.getDN(); subDN != null;
|
subDN = subDN.getParent())
|
{
|
List<SubEntry> subList = dn2CollectiveSubEntry.get(subDN);
|
if (subList != null)
|
{
|
for (SubEntry subEntry : subList)
|
{
|
RFC3672SubtreeSpecification subSpec =
|
subEntry.getSubTreeSpecification();
|
if (subSpec.isWithinScope(entry))
|
{
|
subentries.add(subEntry);
|
}
|
}
|
}
|
}
|
}
|
finally
|
{
|
lock.readLock().unlock();
|
}
|
|
return subentries;
|
}
|
|
/**
|
* {@inheritDoc} In this case, the server will de-register
|
* all subentries associated with the provided backend.
|
*/
|
public void performBackendFinalizationProcessing(Backend backend)
|
{
|
lock.writeLock().lock();
|
try
|
{
|
Iterator<Map.Entry<DN, List<SubEntry>>> setIterator =
|
dn2SubEntry.entrySet().iterator();
|
while (setIterator.hasNext())
|
{
|
Map.Entry<DN, List<SubEntry>> mapEntry = setIterator.next();
|
List<SubEntry> subList = mapEntry.getValue();
|
Iterator<SubEntry> listIterator = subList.iterator();
|
while (listIterator.hasNext())
|
{
|
SubEntry subEntry = listIterator.next();
|
if (backend.handlesEntry(subEntry.getDN()))
|
{
|
listIterator.remove();
|
}
|
}
|
if (subList.isEmpty())
|
{
|
setIterator.remove();
|
}
|
}
|
setIterator = dn2CollectiveSubEntry.entrySet().iterator();
|
while (setIterator.hasNext())
|
{
|
Map.Entry<DN, List<SubEntry>> mapEntry = setIterator.next();
|
List<SubEntry> subList = mapEntry.getValue();
|
Iterator<SubEntry> listIterator = subList.iterator();
|
while (listIterator.hasNext())
|
{
|
SubEntry subEntry = listIterator.next();
|
if (backend.handlesEntry(subEntry.getDN()))
|
{
|
listIterator.remove();
|
}
|
}
|
if (subList.isEmpty())
|
{
|
setIterator.remove();
|
}
|
}
|
}
|
finally
|
{
|
lock.writeLock().unlock();
|
}
|
}
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public PreOperation doPreOperation(
|
PreOperationAddOperation addOperation)
|
{
|
Entry entry = addOperation.getEntryToAdd();
|
|
if (entry.isSubentry() || entry.isLDAPSubentry())
|
{
|
for (SubentryChangeListener changeListener :
|
changeListeners)
|
{
|
try
|
{
|
changeListener.checkSubentryAddAcceptable(entry);
|
}
|
catch (DirectoryException de)
|
{
|
if (debugEnabled())
|
{
|
TRACER.debugCaught(DebugLogLevel.ERROR, de);
|
}
|
|
return PluginResult.PreOperation.stopProcessing(
|
de.getResultCode(), de.getMessageObject());
|
}
|
}
|
}
|
|
return PluginResult.PreOperation.continueOperationProcessing();
|
}
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public PreOperation doPreOperation(
|
PreOperationDeleteOperation deleteOperation)
|
{
|
Entry entry = deleteOperation.getEntryToDelete();
|
|
if (entry.isSubentry() || entry.isLDAPSubentry())
|
{
|
for (SubentryChangeListener changeListener :
|
changeListeners)
|
{
|
try
|
{
|
changeListener.checkSubentryDeleteAcceptable(entry);
|
}
|
catch (DirectoryException de)
|
{
|
if (debugEnabled())
|
{
|
TRACER.debugCaught(DebugLogLevel.ERROR, de);
|
}
|
|
return PluginResult.PreOperation.stopProcessing(
|
de.getResultCode(), de.getMessageObject());
|
}
|
}
|
}
|
|
return PluginResult.PreOperation.continueOperationProcessing();
|
}
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public PreOperation doPreOperation(
|
PreOperationModifyOperation modifyOperation)
|
{
|
Entry oldEntry = modifyOperation.getCurrentEntry();
|
Entry newEntry = modifyOperation.getModifiedEntry();
|
|
if ((newEntry.isSubentry() || newEntry.isLDAPSubentry()) ||
|
(oldEntry.isSubentry() || oldEntry.isLDAPSubentry()))
|
{
|
for (SubentryChangeListener changeListener :
|
changeListeners)
|
{
|
try
|
{
|
changeListener.checkSubentryModifyAcceptable(
|
oldEntry, newEntry);
|
}
|
catch (DirectoryException de)
|
{
|
if (debugEnabled())
|
{
|
TRACER.debugCaught(DebugLogLevel.ERROR, de);
|
}
|
|
return PluginResult.PreOperation.stopProcessing(
|
de.getResultCode(), de.getMessageObject());
|
}
|
}
|
}
|
|
return PluginResult.PreOperation.continueOperationProcessing();
|
}
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public PreOperation doPreOperation(
|
PreOperationModifyDNOperation modifyDNOperation)
|
{
|
Entry oldEntry = modifyDNOperation.getOriginalEntry();
|
Entry newEntry = modifyDNOperation.getUpdatedEntry();
|
|
if (oldEntry.isSubentry() || oldEntry.isLDAPSubentry())
|
{
|
for (SubentryChangeListener changeListener :
|
changeListeners)
|
{
|
try
|
{
|
changeListener.checkSubentryModifyAcceptable(
|
oldEntry, newEntry);
|
}
|
catch (DirectoryException de)
|
{
|
if (debugEnabled())
|
{
|
TRACER.debugCaught(DebugLogLevel.ERROR, de);
|
}
|
|
return PluginResult.PreOperation.stopProcessing(
|
de.getResultCode(), de.getMessageObject());
|
}
|
}
|
}
|
|
return PluginResult.PreOperation.continueOperationProcessing();
|
}
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public PostOperation doPostOperation(
|
PostOperationAddOperation addOperation)
|
{
|
Entry entry = addOperation.getEntryToAdd();
|
|
if (entry.isSubentry() || entry.isLDAPSubentry())
|
{
|
try
|
{
|
addSubEntry(entry);
|
|
// Notify change listeners.
|
for (SubentryChangeListener changeListener :
|
changeListeners)
|
{
|
try
|
{
|
changeListener.handleSubentryAdd(entry);
|
}
|
catch (Exception e)
|
{
|
if (debugEnabled())
|
{
|
TRACER.debugCaught(DebugLogLevel.ERROR, e);
|
}
|
}
|
}
|
}
|
catch (Exception e)
|
{
|
if (debugEnabled())
|
{
|
TRACER.debugCaught(DebugLogLevel.ERROR, e);
|
}
|
|
// FIXME -- Handle this.
|
}
|
}
|
|
return PluginResult.PostOperation.continueOperationProcessing();
|
}
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public PostOperation doPostOperation(
|
PostOperationDeleteOperation deleteOperation)
|
{
|
Entry entry = deleteOperation.getEntryToDelete();
|
|
if (entry.isSubentry() || entry.isLDAPSubentry())
|
{
|
removeSubEntry(entry);
|
|
// Notify change listeners.
|
for (SubentryChangeListener changeListener :
|
changeListeners)
|
{
|
try
|
{
|
changeListener.handleSubentryDelete(entry);
|
}
|
catch (Exception e)
|
{
|
if (debugEnabled())
|
{
|
TRACER.debugCaught(DebugLogLevel.ERROR, e);
|
}
|
}
|
}
|
}
|
|
return PluginResult.PostOperation.continueOperationProcessing();
|
}
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public PostOperation doPostOperation(
|
PostOperationModifyOperation modifyOperation)
|
{
|
Entry oldEntry = modifyOperation.getCurrentEntry();
|
Entry newEntry = modifyOperation.getModifiedEntry();
|
|
boolean notify = false;
|
|
if (oldEntry.isSubentry() || oldEntry.isLDAPSubentry())
|
{
|
removeSubEntry(oldEntry);
|
notify = true;
|
}
|
if (newEntry.isSubentry() || newEntry.isLDAPSubentry())
|
{
|
try
|
{
|
addSubEntry(newEntry);
|
notify = true;
|
}
|
catch (Exception e)
|
{
|
if (debugEnabled())
|
{
|
TRACER.debugCaught(DebugLogLevel.ERROR, e);
|
}
|
|
// FIXME -- Handle this.
|
}
|
}
|
|
if (notify)
|
{
|
// Notify change listeners.
|
for (SubentryChangeListener changeListener :
|
changeListeners)
|
{
|
try
|
{
|
changeListener.handleSubentryModify(
|
oldEntry, newEntry);
|
}
|
catch (Exception e)
|
{
|
if (debugEnabled())
|
{
|
TRACER.debugCaught(DebugLogLevel.ERROR, e);
|
}
|
}
|
}
|
}
|
|
return PluginResult.PostOperation.continueOperationProcessing();
|
}
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public PostOperation doPostOperation(
|
PostOperationModifyDNOperation modifyDNOperation)
|
{
|
Entry oldEntry = modifyDNOperation.getOriginalEntry();
|
Entry newEntry = modifyDNOperation.getUpdatedEntry();
|
|
if (oldEntry.isSubentry() || oldEntry.isLDAPSubentry())
|
{
|
removeSubEntry(oldEntry);
|
try
|
{
|
addSubEntry(newEntry);
|
}
|
catch (Exception e)
|
{
|
if (debugEnabled())
|
{
|
TRACER.debugCaught(DebugLogLevel.ERROR, e);
|
}
|
|
// FIXME -- Handle this.
|
}
|
|
// Notify change listeners.
|
for (SubentryChangeListener changeListener :
|
changeListeners)
|
{
|
try
|
{
|
changeListener.handleSubentryModify(
|
oldEntry, newEntry);
|
}
|
catch (Exception e)
|
{
|
if (debugEnabled())
|
{
|
TRACER.debugCaught(DebugLogLevel.ERROR, e);
|
}
|
}
|
}
|
}
|
|
return PluginResult.PostOperation.continueOperationProcessing();
|
}
|
}
|