// Check for a request to cancel this operation.
checkIfCanceled(false);
AbstractTransaction txn =
new AbstractTransaction(ndbBackend.getRootContainer());
try
{
// Get the current entry from the appropriate backend. If it doesn't
// exist, then fail.
try
{
currentEntry = ndbBackend.getEntryNoCommit(entryDN, txn,
NdbOperation.LockMode.LM_Exclusive);
}
catch (DirectoryException de)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
setResponseData(de);
break modifyDNProcessing;
}
if (getOriginalEntry() == null)
{
// See if one of the entry's ancestors exists.
parentDN = entryDN.getParentDNInSuffix();
while (parentDN != null)
{
try
{
if (DirectoryServer.entryExists(parentDN))
{
setMatchedDN(parentDN);
break;
}
}
catch (Exception e)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
break;
}
parentDN = parentDN.getParentDNInSuffix();
}
setResultCode(ResultCode.NO_SUCH_OBJECT);
appendErrorMessage(ERR_MODDN_NO_CURRENT_ENTRY.get(
String.valueOf(entryDN)));
break modifyDNProcessing;
}
if(!handleConflictResolution()) {
break modifyDNProcessing;
}
// Check to see if there are any controls in the request. If so, then
// see if there is any special processing required.
try
{
handleRequestControls();
}
catch (DirectoryException de)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
setResponseData(de);
break modifyDNProcessing;
}
// Check to see if the client has permission to perform the
// modify DN.
// FIXME: for now assume that this will check all permission
// pertinent to the operation. This includes proxy authorization
// and any other controls specified.
// FIXME: earlier checks to see if the entry or new superior
// already exists may have already exposed sensitive information
// to the client.
try
{
if (!AccessControlConfigManager.getInstance()
.getAccessControlHandler().isAllowed(this))
{
setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
appendErrorMessage(ERR_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS
.get(String.valueOf(entryDN)));
break modifyDNProcessing;
}
}
catch (DirectoryException e)
{
setResultCode(e.getResultCode());
appendErrorMessage(e.getMessageObject());
break modifyDNProcessing;
}
// Duplicate the entry and set its new DN. Also, create an empty list
// to hold the attribute-level modifications.
newEntry = currentEntry.duplicate(false);
newEntry.setDN(newDN);
// init the modifications
addModification(null);
List<Modification> modifications = this.getModifications();
// Apply any changes to the entry based on the change in its RDN. Also,
// perform schema checking on the updated entry.
try
{
applyRDNChanges(modifications);
}
catch (DirectoryException de)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
setResponseData(de);
break modifyDNProcessing;
}
// Check for a request to cancel this operation.
checkIfCanceled(false);
// Get a count of the current number of modifications. The
// pre-operation plugins may alter this list, and we need to be able to
// identify which changes were made after they're done.
int modCount = modifications.size();
// If the operation is not a synchronization operation,
// Invoke the pre-operation modify DN plugins.
if (! isSynchronizationOperation())
{
executePostOpPlugins = true;
PluginResult.PreOperation preOpResult =
pluginConfigManager.invokePreOperationModifyDNPlugins(this);
if (!preOpResult.continueProcessing())
{
setResultCode(preOpResult.getResultCode());
appendErrorMessage(preOpResult.getErrorMessage());
setMatchedDN(preOpResult.getMatchedDN());
setReferralURLs(preOpResult.getReferralURLs());
break modifyDNProcessing;
}
}
// Check to see if any of the pre-operation plugins made any changes to
// the entry. If so, then apply them.
if (modifications.size() > modCount)
{
try
{
applyPreOpModifications(modifications, modCount);
}
catch (DirectoryException de)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
setResponseData(de);
break modifyDNProcessing;
}
}
// Actually perform the modify DN operation.
// This should include taking
// care of any synchronization that might be needed.
try
{
// If it is not a private backend, then check to see if the server or
// backend is operating in read-only mode.
if (! currentBackend.isPrivateBackend())
{
switch (DirectoryServer.getWritabilityMode())
{
case DISABLED:
setResultCode(ResultCode.UNWILLING_TO_PERFORM);
appendErrorMessage(ERR_MODDN_SERVER_READONLY.get(
String.valueOf(entryDN)));
break modifyDNProcessing;
case INTERNAL_ONLY:
if (! (isInternalOperation() || isSynchronizationOperation()))
{
setResultCode(ResultCode.UNWILLING_TO_PERFORM);
appendErrorMessage(ERR_MODDN_SERVER_READONLY.get(
String.valueOf(entryDN)));
break modifyDNProcessing;
}
}
switch (currentBackend.getWritabilityMode())
{
case DISABLED:
setResultCode(ResultCode.UNWILLING_TO_PERFORM);
appendErrorMessage(ERR_MODDN_BACKEND_READONLY.get(
String.valueOf(entryDN)));
break modifyDNProcessing;
case INTERNAL_ONLY:
if (! (isInternalOperation() || isSynchronizationOperation()))
{
setResultCode(ResultCode.UNWILLING_TO_PERFORM);
appendErrorMessage(ERR_MODDN_BACKEND_READONLY.get(
String.valueOf(entryDN)));
break modifyDNProcessing;
}
}
}
if (noOp)
{
appendErrorMessage(INFO_MODDN_NOOP.get());
setResultCode(ResultCode.NO_OPERATION);
}
else
{
if(!processPreOperation()) {
break modifyDNProcessing;
}
ndbBackend.renameEntry(entryDN, newEntry, this, txn);
}
// Attach the pre-read and/or post-read controls to the response if
// appropriate.
processReadEntryControls();
if (! noOp)
{
setResultCode(ResultCode.SUCCESS);
}
}
catch (DirectoryException de)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
setResponseData(de);
break modifyDNProcessing;
}
}
finally
{
processSynchPostOperationPlugins();
try {
txn.close();
} catch (Exception ex) {
if (debugEnabled()) {
TRACER.debugCaught(DebugLogLevel.ERROR, ex);
}
}