Search in sources :

Example 1 with DelegatingTransactionContextRunnable

use of eu.bcvsolutions.idm.core.config.DelegatingTransactionContextRunnable in project CzechIdMng by bcvsolutions.

the class DefaultProvisioningExecutor method executeInternal.

/**
 * We need to wait to transaction commit, when provisioning is executed - all accounts have to be prepared.
 * Next processing is executed outside a transaction
 * => operation states has to be saved in new transactions
 * => rollback on the target system is not possible anyway
 *
 * @param provisioningOperation
 * @return
 */
@TransactionalEventListener
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public SysProvisioningOperationDto executeInternal(SysProvisioningOperationDto provisioningOperation) {
    Assert.notNull(provisioningOperation, "Provisioning operation is required.");
    Assert.notNull(provisioningOperation.getSystemEntity(), "System entity is required.");
    Assert.notNull(provisioningOperation.getProvisioningContext(), "Provisioning context is required.");
    // 
    try {
        boolean checkNotExecuted = provisioningOperation.isSynchronousProvisioning();
        if (provisioningOperationService.isNew(provisioningOperation)) {
            provisioningOperation = persistOperation(provisioningOperation);
            checkNotExecuted = true;
        }
        if (checkNotExecuted && provisioningOperation.getResult() != null && OperationState.NOT_EXECUTED == provisioningOperation.getResult().getState()) {
            return provisioningOperation;
        }
        // 
        CoreEvent<SysProvisioningOperationDto> event = new CoreEvent<SysProvisioningOperationDto>(provisioningOperation.getOperationType(), provisioningOperation);
        try {
            // set a global provisioning timeout even for synchronous call
            FutureTask<EventContext<SysProvisioningOperationDto>> futureTask = new FutureTask<EventContext<SysProvisioningOperationDto>>(new Callable<EventContext<SysProvisioningOperationDto>>() {

                @Override
                public EventContext<SysProvisioningOperationDto> call() {
                    return entityEventManager.process(event);
                }
            });
            // thread pool is not used here
            Thread thread = new Thread(new DelegatingSecurityContextRunnable(new DelegatingTransactionContextRunnable(futureTask)));
            thread.start();
            // 
            // global timeout by configuration
            long timeout = provisioningConfiguration.getTimeout();
            try {
                // TODO: non blocking wait if possible (refactoring is needed + java 9 helps)
                EventContext<SysProvisioningOperationDto> context = futureTask.get(timeout, TimeUnit.MILLISECONDS);
                // 
                return context.getContent();
            } catch (InterruptedException ex) {
                futureTask.cancel(true);
                // propagate exception to upper catch
                throw ex;
            } catch (TimeoutException ex) {
                futureTask.cancel(true);
                // put thread into queue and wait => timeout too => retry mecchanism will work
                throw new ResultCodeException(AccResultCode.PROVISIONING_TIMEOUT, ImmutableMap.of("name", provisioningOperation.getSystemEntityUid(), "system", provisioningOperation.getSystem(), "operationType", provisioningOperation.getOperationType(), "objectClass", provisioningOperation.getProvisioningContext().getConnectorObject().getObjectClass(), "timeout", String.valueOf(timeout)), ex);
            }
        } catch (Exception ex) {
            return provisioningOperationService.handleFailed(provisioningOperation, ex);
        } finally {
            try {
                UUID roleRequestId = provisioningOperation.getRoleRequestId();
                if (roleRequestId != null) {
                    // Check of the state for whole request
                    // Create mock request -> we don't wont load request from DB -> optimization
                    IdmRoleRequestDto mockRequest = new IdmRoleRequestDto();
                    mockRequest.setId(roleRequestId);
                    mockRequest.setState(RoleRequestState.EXECUTED);
                    IdmRoleRequestDto returnedReqeust = roleRequestService.refreshSystemState(mockRequest);
                    OperationResultDto systemState = returnedReqeust.getSystemState();
                    if (systemState == null) {
                    // State on system of request was not changed (may be not all provisioning operations are
                    // resolved)
                    } else {
                        // We have final state on systems
                        IdmRoleRequestDto requestDto = roleRequestService.get(roleRequestId);
                        if (requestDto != null) {
                            requestDto.setSystemState(systemState);
                            roleRequestService.save(requestDto);
                        } else {
                            LOG.info(MessageFormat.format("Refresh role-request system state: Role-request with ID [{0}] was not found (maybe was deleted).", roleRequestId));
                        }
                    }
                }
            } catch (Exception ex) {
                return provisioningOperationService.handleFailed(provisioningOperation, ex);
            }
        }
    } finally {
        UUID eventId = provisioningOperation.getManualEventId();
        if (eventId != null) {
            IdmEntityEventDto startEvent = entityEventManager.getEvent(eventId);
            if (startEvent != null) {
                // Complete a manual event (for ensure end of the sync).
                entityEventManager.completeManualEvent(startEvent);
            }
        }
    }
}
Also used : ResultCodeException(eu.bcvsolutions.idm.core.api.exception.ResultCodeException) OperationResultDto(eu.bcvsolutions.idm.core.api.dto.OperationResultDto) TimeoutException(java.util.concurrent.TimeoutException) ResultCodeException(eu.bcvsolutions.idm.core.api.exception.ResultCodeException) EventContext(eu.bcvsolutions.idm.core.api.event.EventContext) FutureTask(java.util.concurrent.FutureTask) CoreEvent(eu.bcvsolutions.idm.core.api.event.CoreEvent) DelegatingSecurityContextRunnable(org.springframework.security.concurrent.DelegatingSecurityContextRunnable) UUID(java.util.UUID) SysProvisioningOperationDto(eu.bcvsolutions.idm.acc.dto.SysProvisioningOperationDto) DelegatingTransactionContextRunnable(eu.bcvsolutions.idm.core.config.DelegatingTransactionContextRunnable) IdmRoleRequestDto(eu.bcvsolutions.idm.core.api.dto.IdmRoleRequestDto) TimeoutException(java.util.concurrent.TimeoutException) IdmEntityEventDto(eu.bcvsolutions.idm.core.api.dto.IdmEntityEventDto) TransactionalEventListener(org.springframework.transaction.event.TransactionalEventListener) Transactional(org.springframework.transaction.annotation.Transactional)

Aggregations

SysProvisioningOperationDto (eu.bcvsolutions.idm.acc.dto.SysProvisioningOperationDto)1 IdmEntityEventDto (eu.bcvsolutions.idm.core.api.dto.IdmEntityEventDto)1 IdmRoleRequestDto (eu.bcvsolutions.idm.core.api.dto.IdmRoleRequestDto)1 OperationResultDto (eu.bcvsolutions.idm.core.api.dto.OperationResultDto)1 CoreEvent (eu.bcvsolutions.idm.core.api.event.CoreEvent)1 EventContext (eu.bcvsolutions.idm.core.api.event.EventContext)1 ResultCodeException (eu.bcvsolutions.idm.core.api.exception.ResultCodeException)1 DelegatingTransactionContextRunnable (eu.bcvsolutions.idm.core.config.DelegatingTransactionContextRunnable)1 UUID (java.util.UUID)1 FutureTask (java.util.concurrent.FutureTask)1 TimeoutException (java.util.concurrent.TimeoutException)1 DelegatingSecurityContextRunnable (org.springframework.security.concurrent.DelegatingSecurityContextRunnable)1 Transactional (org.springframework.transaction.annotation.Transactional)1 TransactionalEventListener (org.springframework.transaction.event.TransactionalEventListener)1