use of com.unboundid.ldap.sdk.unboundidds.extensions.SubtreeAccessibilityState in project ldapsdk by pingidentity.
the class MoveSubtree method moveSubtreeWithRestrictedAccessibility.
/**
* Performs the real {@code moveSubtreeWithRestrictedAccessibility}
* processing. If a tool is available, this method will update state
* information in that tool so that it can be referenced by a shutdown hook
* in the event that processing is interrupted.
*
* @param tool A reference to a tool instance to be updated with
* state information.
* @param sourceConnection A connection established to the source server.
* It should be authenticated as a user with
* permission to perform all of the operations
* against the source server as referenced above.
* @param targetConnection A connection established to the target server.
* It should be authenticated as a user with
* permission to perform all of the operations
* against the target server as referenced above.
* @param baseDN The base DN for the subtree to move.
* @param sizeLimit The maximum number of entries to be moved. It
* may be less than or equal to zero to indicate
* that no client-side limit should be enforced
* (although the server may still enforce its own
* limit).
* @param opPurposeControl An optional operation purpose request control
* that may be included in all requests sent to the
* source and target servers.
* @param suppressRefInt Indicates whether to include a request control
* causing referential integrity updates to be
* suppressed on the source server.
* @param listener An optional listener that may be invoked during
* the course of moving entries from the source
* server to the target server.
*
* @return An object with information about the result of the attempted
* subtree move.
*/
@NotNull()
private static MoveSubtreeResult moveSubtreeWithRestrictedAccessibility(@Nullable final MoveSubtree tool, @NotNull final LDAPConnection sourceConnection, @NotNull final LDAPConnection targetConnection, @NotNull final String baseDN, final int sizeLimit, @Nullable final OperationPurposeRequestControl opPurposeControl, final boolean suppressRefInt, @Nullable final MoveSubtreeListener listener) {
// Ensure that the subtree is currently accessible in both the source and
// target servers.
final MoveSubtreeResult initialAccessibilityResult = checkInitialAccessibility(sourceConnection, targetConnection, baseDN, opPurposeControl);
if (initialAccessibilityResult != null) {
return initialAccessibilityResult;
}
final StringBuilder errorMsg = new StringBuilder();
final StringBuilder adminMsg = new StringBuilder();
final ReverseComparator<DN> reverseComparator = new ReverseComparator<>();
final TreeSet<DN> sourceEntryDNs = new TreeSet<>(reverseComparator);
final AtomicInteger entriesReadFromSource = new AtomicInteger(0);
final AtomicInteger entriesAddedToTarget = new AtomicInteger(0);
final AtomicInteger entriesDeletedFromSource = new AtomicInteger(0);
final AtomicReference<ResultCode> resultCode = new AtomicReference<>();
boolean sourceServerAltered = false;
boolean targetServerAltered = false;
SubtreeAccessibilityState currentSourceState = SubtreeAccessibilityState.ACCESSIBLE;
SubtreeAccessibilityState currentTargetState = SubtreeAccessibilityState.ACCESSIBLE;
processingBlock: {
// Identify the users authenticated on each connection.
final String sourceUserDN;
final String targetUserDN;
try {
sourceUserDN = getAuthenticatedUserDN(sourceConnection, true, opPurposeControl);
targetUserDN = getAuthenticatedUserDN(targetConnection, false, opPurposeControl);
} catch (final LDAPException le) {
Debug.debugException(le);
resultCode.compareAndSet(null, le.getResultCode());
append(le.getMessage(), errorMsg);
break processingBlock;
}
// Make the subtree hidden on the target server.
try {
setAccessibility(targetConnection, false, baseDN, SubtreeAccessibilityState.HIDDEN, targetUserDN, opPurposeControl);
currentTargetState = SubtreeAccessibilityState.HIDDEN;
setInterruptMessage(tool, WARN_MOVE_SUBTREE_INTERRUPT_MSG_TARGET_HIDDEN.get(baseDN, targetConnection.getConnectedAddress(), targetConnection.getConnectedPort()));
} catch (final LDAPException le) {
Debug.debugException(le);
resultCode.compareAndSet(null, le.getResultCode());
append(le.getMessage(), errorMsg);
break processingBlock;
}
// Make the subtree read-only on the source server.
try {
setAccessibility(sourceConnection, true, baseDN, SubtreeAccessibilityState.READ_ONLY_BIND_ALLOWED, sourceUserDN, opPurposeControl);
currentSourceState = SubtreeAccessibilityState.READ_ONLY_BIND_ALLOWED;
setInterruptMessage(tool, WARN_MOVE_SUBTREE_INTERRUPT_MSG_SOURCE_READ_ONLY.get(baseDN, targetConnection.getConnectedAddress(), targetConnection.getConnectedPort(), sourceConnection.getConnectedAddress(), sourceConnection.getConnectedPort()));
} catch (final LDAPException le) {
Debug.debugException(le);
resultCode.compareAndSet(null, le.getResultCode());
append(le.getMessage(), errorMsg);
break processingBlock;
}
// Perform a search to find all entries in the target subtree, and include
// a search listener that will add each entry to the target server as it
// is returned from the source server.
final Control[] searchControls;
if (opPurposeControl == null) {
searchControls = new Control[] { new DraftLDUPSubentriesRequestControl(true), new ManageDsaITRequestControl(true), new ReturnConflictEntriesRequestControl(true), new SoftDeletedEntryAccessRequestControl(true, true, false), new RealAttributesOnlyRequestControl(true) };
} else {
searchControls = new Control[] { new DraftLDUPSubentriesRequestControl(true), new ManageDsaITRequestControl(true), new ReturnConflictEntriesRequestControl(true), new SoftDeletedEntryAccessRequestControl(true, true, false), new RealAttributesOnlyRequestControl(true), opPurposeControl };
}
final MoveSubtreeAccessibilitySearchListener searchListener = new MoveSubtreeAccessibilitySearchListener(tool, baseDN, sourceConnection, targetConnection, resultCode, errorMsg, entriesReadFromSource, entriesAddedToTarget, sourceEntryDNs, opPurposeControl, listener);
final SearchRequest searchRequest = new SearchRequest(searchListener, searchControls, baseDN, SearchScope.SUB, DereferencePolicy.NEVER, sizeLimit, 0, false, Filter.createPresenceFilter("objectClass"), "*", "+");
SearchResult searchResult;
try {
searchResult = sourceConnection.search(searchRequest);
} catch (final LDAPSearchException lse) {
Debug.debugException(lse);
searchResult = lse.getSearchResult();
}
if (entriesAddedToTarget.get() > 0) {
targetServerAltered = true;
}
if (searchResult.getResultCode() != ResultCode.SUCCESS) {
resultCode.compareAndSet(null, searchResult.getResultCode());
append(ERR_MOVE_SUBTREE_SEARCH_FAILED.get(baseDN, searchResult.getDiagnosticMessage()), errorMsg);
final AtomicInteger deleteCount = new AtomicInteger(0);
if (targetServerAltered) {
deleteEntries(targetConnection, false, sourceEntryDNs, opPurposeControl, false, null, deleteCount, resultCode, errorMsg);
entriesAddedToTarget.addAndGet(0 - deleteCount.get());
if (entriesAddedToTarget.get() == 0) {
targetServerAltered = false;
} else {
append(ERR_MOVE_SUBTREE_TARGET_NOT_DELETED_ADMIN_ACTION.get(baseDN), adminMsg);
}
}
break processingBlock;
}
// If an error occurred during add processing, then fail.
if (resultCode.get() != null) {
final AtomicInteger deleteCount = new AtomicInteger(0);
if (targetServerAltered) {
deleteEntries(targetConnection, false, sourceEntryDNs, opPurposeControl, false, null, deleteCount, resultCode, errorMsg);
entriesAddedToTarget.addAndGet(0 - deleteCount.get());
if (entriesAddedToTarget.get() == 0) {
targetServerAltered = false;
} else {
append(ERR_MOVE_SUBTREE_TARGET_NOT_DELETED_ADMIN_ACTION.get(baseDN), adminMsg);
}
}
break processingBlock;
}
// Make the subtree read-only on the target server.
try {
setAccessibility(targetConnection, true, baseDN, SubtreeAccessibilityState.READ_ONLY_BIND_ALLOWED, targetUserDN, opPurposeControl);
currentTargetState = SubtreeAccessibilityState.READ_ONLY_BIND_ALLOWED;
setInterruptMessage(tool, WARN_MOVE_SUBTREE_INTERRUPT_MSG_TARGET_READ_ONLY.get(baseDN, sourceConnection.getConnectedAddress(), sourceConnection.getConnectedPort(), targetConnection.getConnectedAddress(), targetConnection.getConnectedPort()));
} catch (final LDAPException le) {
Debug.debugException(le);
resultCode.compareAndSet(null, le.getResultCode());
append(le.getMessage(), errorMsg);
break processingBlock;
}
// Make the subtree hidden on the source server.
try {
setAccessibility(sourceConnection, true, baseDN, SubtreeAccessibilityState.HIDDEN, sourceUserDN, opPurposeControl);
currentSourceState = SubtreeAccessibilityState.HIDDEN;
setInterruptMessage(tool, WARN_MOVE_SUBTREE_INTERRUPT_MSG_SOURCE_HIDDEN.get(baseDN, sourceConnection.getConnectedAddress(), sourceConnection.getConnectedPort(), targetConnection.getConnectedAddress(), targetConnection.getConnectedPort()));
} catch (final LDAPException le) {
Debug.debugException(le);
resultCode.compareAndSet(null, le.getResultCode());
append(le.getMessage(), errorMsg);
break processingBlock;
}
// Make the subtree accessible on the target server.
try {
setAccessibility(targetConnection, true, baseDN, SubtreeAccessibilityState.ACCESSIBLE, targetUserDN, opPurposeControl);
currentTargetState = SubtreeAccessibilityState.ACCESSIBLE;
setInterruptMessage(tool, WARN_MOVE_SUBTREE_INTERRUPT_MSG_TARGET_ACCESSIBLE.get(baseDN, sourceConnection.getConnectedAddress(), sourceConnection.getConnectedPort(), targetConnection.getConnectedAddress(), targetConnection.getConnectedPort()));
} catch (final LDAPException le) {
Debug.debugException(le);
resultCode.compareAndSet(null, le.getResultCode());
append(le.getMessage(), errorMsg);
break processingBlock;
}
// Delete each of the entries in the source server. The map should
// already be sorted in reverse order (as a result of the comparator used
// when creating it), so it will guarantee children are deleted before
// their parents.
final boolean deleteSuccessful = deleteEntries(sourceConnection, true, sourceEntryDNs, opPurposeControl, suppressRefInt, listener, entriesDeletedFromSource, resultCode, errorMsg);
sourceServerAltered = (entriesDeletedFromSource.get() != 0);
if (!deleteSuccessful) {
append(ERR_MOVE_SUBTREE_SOURCE_NOT_DELETED_ADMIN_ACTION.get(baseDN), adminMsg);
break processingBlock;
}
// Make the subtree accessible on the source server.
try {
setAccessibility(sourceConnection, true, baseDN, SubtreeAccessibilityState.ACCESSIBLE, sourceUserDN, opPurposeControl);
currentSourceState = SubtreeAccessibilityState.ACCESSIBLE;
setInterruptMessage(tool, null);
} catch (final LDAPException le) {
Debug.debugException(le);
resultCode.compareAndSet(null, le.getResultCode());
append(le.getMessage(), errorMsg);
break processingBlock;
}
}
// then accessible, then generate an admin action message.
if (currentSourceState != SubtreeAccessibilityState.ACCESSIBLE) {
if (!sourceServerAltered) {
try {
setAccessibility(sourceConnection, true, baseDN, SubtreeAccessibilityState.ACCESSIBLE, null, opPurposeControl);
currentSourceState = SubtreeAccessibilityState.ACCESSIBLE;
} catch (final LDAPException le) {
Debug.debugException(le);
}
}
if (currentSourceState != SubtreeAccessibilityState.ACCESSIBLE) {
append(ERR_MOVE_SUBTREE_SOURCE_LEFT_INACCESSIBLE.get(currentSourceState, baseDN), adminMsg);
}
}
// then accessible, then generate an admin action message.
if (currentTargetState != SubtreeAccessibilityState.ACCESSIBLE) {
if (!targetServerAltered) {
try {
setAccessibility(targetConnection, false, baseDN, SubtreeAccessibilityState.ACCESSIBLE, null, opPurposeControl);
currentTargetState = SubtreeAccessibilityState.ACCESSIBLE;
} catch (final LDAPException le) {
Debug.debugException(le);
}
}
if (currentTargetState != SubtreeAccessibilityState.ACCESSIBLE) {
append(ERR_MOVE_SUBTREE_TARGET_LEFT_INACCESSIBLE.get(currentTargetState, baseDN), adminMsg);
}
}
// Construct the result to return to the client.
resultCode.compareAndSet(null, ResultCode.SUCCESS);
final String errorMessage;
if (errorMsg.length() > 0) {
errorMessage = errorMsg.toString();
} else {
errorMessage = null;
}
final String adminActionRequired;
if (adminMsg.length() > 0) {
adminActionRequired = adminMsg.toString();
} else {
adminActionRequired = null;
}
return new MoveSubtreeResult(resultCode.get(), errorMessage, adminActionRequired, sourceServerAltered, targetServerAltered, entriesReadFromSource.get(), entriesAddedToTarget.get(), entriesDeletedFromSource.get());
}
use of com.unboundid.ldap.sdk.unboundidds.extensions.SubtreeAccessibilityState in project ldapsdk by pingidentity.
the class SubtreeAccessibility method doSet.
/**
* Does the work necessary to update a subtree accessibility restriction
* defined in the server.
*
* @param connection The connection to use to communicate with the server.
*
* @return A result code with information about the result of operation
* processing.
*/
@NotNull()
private ResultCode doSet(@NotNull final LDAPConnection connection) {
final SubtreeAccessibilityState state = SubtreeAccessibilityState.forName(accessibilityState.getValue());
if (state == null) {
// This should never happen.
err("Unsupported subtree accessibility state ", accessibilityState.getValue());
return ResultCode.PARAM_ERROR;
}
final SetSubtreeAccessibilityExtendedRequest request;
switch(state) {
case ACCESSIBLE:
request = SetSubtreeAccessibilityExtendedRequest.createSetAccessibleRequest(baseDN.getStringValue());
break;
case READ_ONLY_BIND_ALLOWED:
request = SetSubtreeAccessibilityExtendedRequest.createSetReadOnlyRequest(baseDN.getStringValue(), true, bypassUserDN.getStringValue());
break;
case READ_ONLY_BIND_DENIED:
request = SetSubtreeAccessibilityExtendedRequest.createSetReadOnlyRequest(baseDN.getStringValue(), false, bypassUserDN.getStringValue());
break;
case HIDDEN:
request = SetSubtreeAccessibilityExtendedRequest.createSetHiddenRequest(baseDN.getStringValue(), bypassUserDN.getStringValue());
break;
default:
// This should never happen.
err("Unsupported subtree accessibility state ", state.getStateName());
return ResultCode.PARAM_ERROR;
}
final ExtendedResult result;
try {
result = connection.processExtendedOperation(request);
} catch (final LDAPException le) {
Debug.debugException(le);
err("An error occurred while attempting to invoke the set subtree " + "accessibility request: ", StaticUtils.getExceptionMessage(le));
return le.getResultCode();
}
if (result.getResultCode() == ResultCode.SUCCESS) {
out("Successfully set an accessibility state of ", state.getStateName(), " for subtree ", baseDN.getStringValue());
} else {
out("Unable to set an accessibility state of ", state.getStateName(), " for subtree ", baseDN.getStringValue(), ": ", result.getDiagnosticMessage());
}
return result.getResultCode();
}
Aggregations