use of com.unboundid.ldap.sdk.extensions.EndTransactionExtendedRequest in project ldapsdk by pingidentity.
the class TransactionExtendedOperationHandlerTestCase method testFailedTransaction.
/**
* Provides a test case for a transaction in which one of the operations
* fails after other operations that should have succeeded.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test()
public void testFailedTransaction() throws Exception {
final TestUnsolicitedNotificationHandler unsolicitedNotificationHandler = new TestUnsolicitedNotificationHandler();
final LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions();
connectionOptions.setUnsolicitedNotificationHandler(unsolicitedNotificationHandler);
final InMemoryDirectoryServer ds = getTestDS(true, true);
final LDAPConnection conn = ds.getConnection(connectionOptions);
assertEquals(unsolicitedNotificationHandler.getNotificationCount(), 0);
ds.assertEntryExists("dc=example,dc=com");
ds.assertEntryExists("ou=People,dc=example,dc=com");
ds.assertEntryExists("uid=test.user,ou=People,dc=example,dc=com");
ds.assertEntryMissing("ou=test,dc=example,dc=com");
ds.assertEntryMissing("uid=test.user,ou=test,dc=example,dc=com");
final StartTransactionExtendedResult startTxnResult = (StartTransactionExtendedResult) conn.processExtendedOperation(new StartTransactionExtendedRequest());
assertResultCodeEquals(startTxnResult, ResultCode.SUCCESS);
final ASN1OctetString txnID = startTxnResult.getTransactionID();
assertNotNull(txnID);
final TransactionSpecificationRequestControl txnControl = new TransactionSpecificationRequestControl(txnID);
ds.assertEntryExists("dc=example,dc=com");
ds.assertEntryExists("ou=People,dc=example,dc=com");
ds.assertEntryExists("uid=test.user,ou=People,dc=example,dc=com");
ds.assertEntryMissing("ou=test,dc=example,dc=com");
ds.assertEntryMissing("uid=test.user,ou=test,dc=example,dc=com");
final AddRequest addRequest = new AddRequest("dn: ou=test,dc=example,dc=com", "objectClass: top", "objectClass: organizationalUnit", "ou: test");
addRequest.setControls(txnControl);
assertResultCodeEquals(conn, addRequest, ResultCode.SUCCESS);
ds.assertEntryExists("dc=example,dc=com");
ds.assertEntryExists("ou=People,dc=example,dc=com");
ds.assertEntryExists("uid=test.user,ou=People,dc=example,dc=com");
ds.assertEntryMissing("ou=test,dc=example,dc=com");
ds.assertEntryMissing("uid=test.user,ou=test,dc=example,dc=com");
final ModifyRequest modifyRequest = new ModifyRequest("dn: uid=test.user,ou=People,dc=example,dc=com", "changeType: modify", "replace: description", "description: foo");
modifyRequest.setControls(txnControl);
assertResultCodeEquals(conn, modifyRequest, ResultCode.SUCCESS);
ds.assertEntryExists("dc=example,dc=com");
ds.assertEntryExists("ou=People,dc=example,dc=com");
ds.assertEntryExists("uid=test.user,ou=People,dc=example,dc=com");
ds.assertEntryMissing("ou=test,dc=example,dc=com");
ds.assertEntryMissing("uid=test.user,ou=test,dc=example,dc=com");
final ModifyDNRequest modifyDNRequest = new ModifyDNRequest("uid=test.user,ou=People,dc=example,dc=com", "uid=test.user", false, "ou=test,dc=example,dc=com");
modifyDNRequest.setControls(txnControl);
assertResultCodeEquals(conn, modifyDNRequest, ResultCode.SUCCESS);
ds.assertEntryExists("dc=example,dc=com");
ds.assertEntryExists("ou=People,dc=example,dc=com");
ds.assertEntryExists("uid=test.user,ou=People,dc=example,dc=com");
ds.assertEntryMissing("ou=test,dc=example,dc=com");
ds.assertEntryMissing("uid=test.user,ou=test,dc=example,dc=com");
final DeleteRequest deleteRequest = new DeleteRequest("ou=missing,dc=example,dc=com");
deleteRequest.setControls(txnControl);
assertResultCodeEquals(conn, deleteRequest, ResultCode.SUCCESS);
ds.assertEntryExists("dc=example,dc=com");
ds.assertEntryExists("ou=People,dc=example,dc=com");
ds.assertEntryExists("uid=test.user,ou=People,dc=example,dc=com");
ds.assertEntryMissing("ou=test,dc=example,dc=com");
ds.assertEntryMissing("uid=test.user,ou=test,dc=example,dc=com");
final EndTransactionExtendedResult endTxnResult = (EndTransactionExtendedResult) conn.processExtendedOperation(new EndTransactionExtendedRequest(txnID, true));
assertResultCodeEquals(endTxnResult, ResultCode.NO_SUCH_OBJECT);
assertTrue(endTxnResult.getFailedOpMessageID() > 0);
assertEquals(endTxnResult.getFailedOpMessageID(), deleteRequest.getLastMessageID());
assertNotNull(endTxnResult.getOperationResponseControls());
assertTrue(endTxnResult.getOperationResponseControls().isEmpty());
ds.assertEntryExists("dc=example,dc=com");
ds.assertEntryExists("ou=People,dc=example,dc=com");
ds.assertEntryExists("uid=test.user,ou=People,dc=example,dc=com");
ds.assertEntryMissing("ou=test,dc=example,dc=com");
ds.assertEntryMissing("uid=test.user,ou=test,dc=example,dc=com");
conn.close();
assertEquals(unsolicitedNotificationHandler.getNotificationCount(), 0);
}
use of com.unboundid.ldap.sdk.extensions.EndTransactionExtendedRequest in project ldapsdk by pingidentity.
the class TransactionExtendedOperationHandlerTestCase method testFailedModifyDNInTransaction.
/**
* Provides a test case for a transaction in which a modify DN operation fails
* after other operations that should have succeeded.
*
* @throws Exception If an unexpected problem occurs.
*/
@Test()
public void testFailedModifyDNInTransaction() throws Exception {
final TestUnsolicitedNotificationHandler unsolicitedNotificationHandler = new TestUnsolicitedNotificationHandler();
final LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions();
connectionOptions.setUnsolicitedNotificationHandler(unsolicitedNotificationHandler);
final InMemoryDirectoryServer ds = getTestDS(true, true);
final LDAPConnection conn = ds.getConnection(connectionOptions);
assertEquals(unsolicitedNotificationHandler.getNotificationCount(), 0);
ds.assertEntryExists("dc=example,dc=com");
ds.assertEntryExists("ou=People,dc=example,dc=com");
ds.assertEntryExists("uid=test.user,ou=People,dc=example,dc=com");
ds.assertEntryMissing("ou=test,dc=example,dc=com");
ds.assertEntryMissing("uid=test.user,ou=test,dc=example,dc=com");
final StartTransactionExtendedResult startTxnResult = (StartTransactionExtendedResult) conn.processExtendedOperation(new StartTransactionExtendedRequest());
assertResultCodeEquals(startTxnResult, ResultCode.SUCCESS);
final ASN1OctetString txnID = startTxnResult.getTransactionID();
assertNotNull(txnID);
final TransactionSpecificationRequestControl txnControl = new TransactionSpecificationRequestControl(txnID);
final AddRequest addRequest = new AddRequest("dn: ou=test,dc=example,dc=com", "objectClass: top", "objectClass: organizationalUnit", "ou: test");
addRequest.setControls(txnControl);
assertResultCodeEquals(conn, addRequest, ResultCode.SUCCESS);
final ModifyDNRequest modifyDNRequest = new ModifyDNRequest("ou=Missing,dc=example,dc=com", "ou=Still Missing", true);
modifyDNRequest.setControls(txnControl);
assertResultCodeEquals(conn, modifyDNRequest, ResultCode.SUCCESS);
final EndTransactionExtendedResult endTxnResult = (EndTransactionExtendedResult) conn.processExtendedOperation(new EndTransactionExtendedRequest(txnID, true));
assertResultCodeEquals(endTxnResult, ResultCode.NO_SUCH_OBJECT);
assertTrue(endTxnResult.getFailedOpMessageID() > 0);
assertEquals(endTxnResult.getFailedOpMessageID(), modifyDNRequest.getLastMessageID());
assertNotNull(endTxnResult.getOperationResponseControls());
assertTrue(endTxnResult.getOperationResponseControls().isEmpty());
ds.assertEntryExists("dc=example,dc=com");
ds.assertEntryExists("ou=People,dc=example,dc=com");
ds.assertEntryExists("uid=test.user,ou=People,dc=example,dc=com");
ds.assertEntryMissing("ou=test,dc=example,dc=com");
ds.assertEntryMissing("uid=test.user,ou=test,dc=example,dc=com");
conn.close();
assertEquals(unsolicitedNotificationHandler.getNotificationCount(), 0);
}
use of com.unboundid.ldap.sdk.extensions.EndTransactionExtendedRequest in project ldapsdk by pingidentity.
the class TransactionExtendedOperationHandler method handleEndTransaction.
/**
* Performs the appropriate processing for an end transaction extended
* request.
*
* @param handler The in-memory request handler that received the request.
* @param messageID The message ID for the associated request.
* @param request The extended request that was received.
*
* @return The result for the extended operation processing.
*/
@NotNull()
private static EndTransactionExtendedResult handleEndTransaction(@NotNull final InMemoryRequestHandler handler, final int messageID, @NotNull final ExtendedRequest request) {
// Get information about any transaction currently in progress on the
// connection. If there isn't one, then fail.
final Map<String, Object> connectionState = handler.getConnectionState();
final ObjectPair<?, ?> txnInfo = (ObjectPair<?, ?>) connectionState.remove(STATE_VARIABLE_TXN_INFO);
if (txnInfo == null) {
return new EndTransactionExtendedResult(messageID, ResultCode.CONSTRAINT_VIOLATION, ERR_TXN_EXTOP_END_NO_ACTIVE_TXN.get(), null, null, null, null, null);
}
// Make sure that we can decode the end transaction request.
final ASN1OctetString existingTxnID = (ASN1OctetString) txnInfo.getFirst();
final EndTransactionExtendedRequest endTxnRequest;
try {
endTxnRequest = new EndTransactionExtendedRequest(request);
} catch (final LDAPException le) {
Debug.debugException(le);
try {
handler.getClientConnection().sendUnsolicitedNotification(new AbortedTransactionExtendedResult(existingTxnID, ResultCode.PROTOCOL_ERROR, ERR_TXN_EXTOP_ABORTED_BY_MALFORMED_END_TXN.get(existingTxnID.stringValue()), null, null, null));
} catch (final LDAPException le2) {
Debug.debugException(le2);
}
return new EndTransactionExtendedResult(messageID, ResultCode.PROTOCOL_ERROR, le.getMessage(), null, null, null, null, null);
}
// Make sure that the transaction ID of the existing transaction matches the
// transaction ID from the end transaction request.
final ASN1OctetString targetTxnID = endTxnRequest.getTransactionID();
if (!existingTxnID.stringValue().equals(targetTxnID.stringValue())) {
// transaction has been aborted.
try {
handler.getClientConnection().sendUnsolicitedNotification(new AbortedTransactionExtendedResult(existingTxnID, ResultCode.CONSTRAINT_VIOLATION, ERR_TXN_EXTOP_ABORTED_BY_WRONG_END_TXN.get(existingTxnID.stringValue(), targetTxnID.stringValue()), null, null, null));
} catch (final LDAPException le) {
Debug.debugException(le);
return new EndTransactionExtendedResult(messageID, le.getResultCode(), le.getMessage(), le.getMatchedDN(), le.getReferralURLs(), null, null, le.getResponseControls());
}
return new EndTransactionExtendedResult(messageID, ResultCode.CONSTRAINT_VIOLATION, ERR_TXN_EXTOP_END_WRONG_TXN.get(targetTxnID.stringValue(), existingTxnID.stringValue()), null, null, null, null, null);
}
// If the transaction should be aborted, then we can just send the response.
if (!endTxnRequest.commit()) {
return new EndTransactionExtendedResult(messageID, ResultCode.SUCCESS, INFO_TXN_EXTOP_END_TXN_ABORTED.get(existingTxnID.stringValue()), null, null, null, null, null);
}
// If we've gotten here, then we'll try to commit the transaction. First,
// get a snapshot of the current state so that we can roll back to it if
// necessary.
final InMemoryDirectoryServerSnapshot snapshot = handler.createSnapshot();
boolean rollBack = true;
try {
// Create a map to hold information about response controls from
// operations processed as part of the transaction.
final List<?> requestMessages = (List<?>) txnInfo.getSecond();
final Map<Integer, Control[]> opResponseControls = new LinkedHashMap<>(StaticUtils.computeMapCapacity(requestMessages.size()));
// Iterate through the requests that have been submitted as part of the
// transaction and attempt to process them.
ResultCode resultCode = ResultCode.SUCCESS;
String diagnosticMessage = null;
String failedOpType = null;
Integer failedOpMessageID = null;
txnOpLoop: for (final Object o : requestMessages) {
final LDAPMessage m = (LDAPMessage) o;
switch(m.getProtocolOpType()) {
case LDAPMessage.PROTOCOL_OP_TYPE_ADD_REQUEST:
final LDAPMessage addResponseMessage = handler.processAddRequest(m.getMessageID(), m.getAddRequestProtocolOp(), m.getControls());
final AddResponseProtocolOp addResponseOp = addResponseMessage.getAddResponseProtocolOp();
final List<Control> addControls = addResponseMessage.getControls();
if ((addControls != null) && (!addControls.isEmpty())) {
final Control[] controls = new Control[addControls.size()];
addControls.toArray(controls);
opResponseControls.put(m.getMessageID(), controls);
}
if (addResponseOp.getResultCode() != ResultCode.SUCCESS_INT_VALUE) {
resultCode = ResultCode.valueOf(addResponseOp.getResultCode());
diagnosticMessage = addResponseOp.getDiagnosticMessage();
failedOpType = INFO_TXN_EXTOP_OP_TYPE_ADD.get();
failedOpMessageID = m.getMessageID();
break txnOpLoop;
}
break;
case LDAPMessage.PROTOCOL_OP_TYPE_DELETE_REQUEST:
final LDAPMessage deleteResponseMessage = handler.processDeleteRequest(m.getMessageID(), m.getDeleteRequestProtocolOp(), m.getControls());
final DeleteResponseProtocolOp deleteResponseOp = deleteResponseMessage.getDeleteResponseProtocolOp();
final List<Control> deleteControls = deleteResponseMessage.getControls();
if ((deleteControls != null) && (!deleteControls.isEmpty())) {
final Control[] controls = new Control[deleteControls.size()];
deleteControls.toArray(controls);
opResponseControls.put(m.getMessageID(), controls);
}
if (deleteResponseOp.getResultCode() != ResultCode.SUCCESS_INT_VALUE) {
resultCode = ResultCode.valueOf(deleteResponseOp.getResultCode());
diagnosticMessage = deleteResponseOp.getDiagnosticMessage();
failedOpType = INFO_TXN_EXTOP_OP_TYPE_DELETE.get();
failedOpMessageID = m.getMessageID();
break txnOpLoop;
}
break;
case LDAPMessage.PROTOCOL_OP_TYPE_MODIFY_REQUEST:
final LDAPMessage modifyResponseMessage = handler.processModifyRequest(m.getMessageID(), m.getModifyRequestProtocolOp(), m.getControls());
final ModifyResponseProtocolOp modifyResponseOp = modifyResponseMessage.getModifyResponseProtocolOp();
final List<Control> modifyControls = modifyResponseMessage.getControls();
if ((modifyControls != null) && (!modifyControls.isEmpty())) {
final Control[] controls = new Control[modifyControls.size()];
modifyControls.toArray(controls);
opResponseControls.put(m.getMessageID(), controls);
}
if (modifyResponseOp.getResultCode() != ResultCode.SUCCESS_INT_VALUE) {
resultCode = ResultCode.valueOf(modifyResponseOp.getResultCode());
diagnosticMessage = modifyResponseOp.getDiagnosticMessage();
failedOpType = INFO_TXN_EXTOP_OP_TYPE_MODIFY.get();
failedOpMessageID = m.getMessageID();
break txnOpLoop;
}
break;
case LDAPMessage.PROTOCOL_OP_TYPE_MODIFY_DN_REQUEST:
final LDAPMessage modifyDNResponseMessage = handler.processModifyDNRequest(m.getMessageID(), m.getModifyDNRequestProtocolOp(), m.getControls());
final ModifyDNResponseProtocolOp modifyDNResponseOp = modifyDNResponseMessage.getModifyDNResponseProtocolOp();
final List<Control> modifyDNControls = modifyDNResponseMessage.getControls();
if ((modifyDNControls != null) && (!modifyDNControls.isEmpty())) {
final Control[] controls = new Control[modifyDNControls.size()];
modifyDNControls.toArray(controls);
opResponseControls.put(m.getMessageID(), controls);
}
if (modifyDNResponseOp.getResultCode() != ResultCode.SUCCESS_INT_VALUE) {
resultCode = ResultCode.valueOf(modifyDNResponseOp.getResultCode());
diagnosticMessage = modifyDNResponseOp.getDiagnosticMessage();
failedOpType = INFO_TXN_EXTOP_OP_TYPE_MODIFY_DN.get();
failedOpMessageID = m.getMessageID();
break txnOpLoop;
}
break;
}
}
if (resultCode == ResultCode.SUCCESS) {
diagnosticMessage = INFO_TXN_EXTOP_COMMITTED.get(existingTxnID.stringValue());
rollBack = false;
} else {
diagnosticMessage = ERR_TXN_EXTOP_COMMIT_FAILED.get(existingTxnID.stringValue(), failedOpType, failedOpMessageID, diagnosticMessage);
}
return new EndTransactionExtendedResult(messageID, resultCode, diagnosticMessage, null, null, failedOpMessageID, opResponseControls, null);
} finally {
if (rollBack) {
handler.restoreSnapshot(snapshot);
}
}
}
Aggregations