throws CanceledOperationException
{
boolean executePostOpPlugins = false;
this.backend = wfe.getBackend();
ClientConnection clientConnection = getClientConnection();
// Get the plugin config manager that will be used for invoking plugins.
PluginConfigManager pluginConfigManager =
DirectoryServer.getPluginConfigManager();
// Check for a request to cancel this operation.
checkIfCanceled(false);
// Create a labeled block of code that we can break out of if a problem is
// detected.
addProcessing:
{
// Process the entry DN and set of attributes to convert them from their
// raw forms as provided by the client to the forms required for the rest
// of the add processing.
entryDN = getEntryDN();
if (entryDN == null)
{
break addProcessing;
}
// Check for a request to cancel this operation.
checkIfCanceled(false);
// Grab a read lock on the parent entry, if there is one. We need to do
// this to ensure that the parent is not deleted or renamed while this add
// is in progress, and we could also need it to check the entry against
// a DIT structure rule.
Lock parentLock = null;
Lock entryLock = null;
DN parentDN = entryDN.getParentDNInSuffix();
try
{
parentLock = lockParent(parentDN);
}
catch (DirectoryException de)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
setResponseData(de);
break addProcessing;
}
try
{
// Check for a request to cancel this operation.
checkIfCanceled(false);
// Grab a write lock on the target entry. We'll need to do this
// eventually anyway, and we want to make sure that the two locks are
// always released when exiting this method, no matter what. Since
// the entry shouldn't exist yet, locking earlier than necessary
// shouldn't cause a problem.
for (int i=0; i < 3; i++)
{
entryLock = LockManager.lockWrite(entryDN);
if (entryLock != null)
{
break;
}
}
if (entryLock == null)
{
setResultCode(DirectoryServer.getServerErrorResultCode());
appendErrorMessage(ERR_ADD_CANNOT_LOCK_ENTRY.get(
String.valueOf(entryDN)));
break addProcessing;
}
// Invoke any conflict resolution processing that might be needed by the
// synchronization provider.
for (SynchronizationProvider provider :
DirectoryServer.getSynchronizationProviders())
{
try
{
SynchronizationProviderResult result =
provider.handleConflictResolution(this);
if (! result.continueProcessing())
{
setResultCode(result.getResultCode());
appendErrorMessage(result.getErrorMessage());
setMatchedDN(result.getMatchedDN());
setReferralURLs(result.getReferralURLs());
break addProcessing;
}
}
catch (DirectoryException de)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
logError(ERR_ADD_SYNCH_CONFLICT_RESOLUTION_FAILED.get(
getConnectionID(), getOperationID(),
getExceptionMessage(de)));
setResponseData(de);
break addProcessing;
}
}
objectClasses = getObjectClasses();
userAttributes = getUserAttributes();
operationalAttributes = getOperationalAttributes();
if ((objectClasses == null ) || (userAttributes == null) ||
(operationalAttributes == null))
{
break addProcessing;
}
for (AttributeType at : userAttributes.keySet())
{
// If the attribute type is marked "NO-USER-MODIFICATION" then fail
// unless this is an internal operation or is related to
// synchronization in some way.
// This must be done before running the password policy code
// and any other code that may add attributes marked as
// "NO-USER-MODIFICATION"
//
// Note that doing this checks at this time
// of the processing does not make it possible for pre-parse plugins
// to add NO-USER-MODIFICATION attributes to the entry.
if (at.isNoUserModification())
{
if (! (isInternalOperation() || isSynchronizationOperation()))
{
setResultCode(ResultCode.UNWILLING_TO_PERFORM);
appendErrorMessage(ERR_ADD_ATTR_IS_NO_USER_MOD.get(
String.valueOf(entryDN),
at.getNameOrOID()));
break addProcessing;
}
}
}
for (AttributeType at : operationalAttributes.keySet())
{
if (at.isNoUserModification())
{
if (! (isInternalOperation() || isSynchronizationOperation()))
{
setResultCode(ResultCode.UNWILLING_TO_PERFORM);
appendErrorMessage(ERR_ADD_ATTR_IS_NO_USER_MOD.get(
String.valueOf(entryDN),
at.getNameOrOID()));
break addProcessing;
}
}
}
// Check to see if the entry already exists. We do this before
// checking whether the parent exists to ensure a referral entry
// above the parent results in a correct referral.
try
{
if (DirectoryServer.entryExists(entryDN))
{
setResultCode(ResultCode.ENTRY_ALREADY_EXISTS);
appendErrorMessage(ERR_ADD_ENTRY_ALREADY_EXISTS.get(
String.valueOf(entryDN)));
break addProcessing;
}
}
catch (DirectoryException de)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
setResponseData(de);
break addProcessing;
}
// Get the parent entry, if it exists.
Entry parentEntry = null;
if (parentDN != null)
{
try
{
parentEntry = DirectoryServer.getEntry(parentDN);
if (parentEntry == null)
{
DN matchedDN = parentDN.getParentDNInSuffix();
while (matchedDN != null)
{
try
{
if (DirectoryServer.entryExists(matchedDN))
{
setMatchedDN(matchedDN);
break;
}
}
catch (Exception e)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
break;
}
matchedDN = matchedDN.getParentDNInSuffix();
}
// The parent doesn't exist, so this add can't be successful.
setResultCode(ResultCode.NO_SUCH_OBJECT);
appendErrorMessage(ERR_ADD_NO_PARENT.get(String.valueOf(entryDN),
String.valueOf(parentDN)));
break addProcessing;
}
}
catch (DirectoryException de)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
setResponseData(de);
break addProcessing;
}
}
// Check to make sure that all of the RDN attributes are included as
// attribute values. If not, then either add them or report an error.
try
{
addRDNAttributesIfNecessary();
}
catch (DirectoryException de)
{
if (debugEnabled())
{
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
setResponseData(de);
break addProcessing;
}
//Add any superior objectclass(s) missing in an entries
//objectclass map.
addSuperiorObjectClasses(objectClasses);
// Create an entry object to encapsulate the set of attributes and
// objectclasses.
entry = new Entry(entryDN, objectClasses, userAttributes,
operationalAttributes);
// Check to see if the entry includes a privilege specification. If so,
// then the requester must have the PRIVILEGE_CHANGE privilege.
AttributeType privType =
DirectoryServer.getAttributeType(OP_ATTR_PRIVILEGE_NAME, true);
if (entry.hasAttribute(privType) &&
(! clientConnection.hasPrivilege(Privilege.PRIVILEGE_CHANGE, this)))
{
appendErrorMessage(
ERR_ADD_CHANGE_PRIVILEGE_INSUFFICIENT_PRIVILEGES.get());
setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);