use of eu.bcvsolutions.idm.core.api.event.CoreEvent in project CzechIdMng by bcvsolutions.
the class DefaultFormService method saveFormInstance.
/**
* {@inheritDoc}
*
* TODO: validations by given form definition? I don't think, it will not be
* useful in synchronization etc. - only FE validations will be enough ...
*/
@Override
@Transactional
public IdmFormInstanceDto saveFormInstance(Identifiable owner, IdmFormDefinitionDto formDefinition, List<IdmFormValueDto> values) {
FormableEntity ownerEntity = getOwnerEntity(owner);
Assert.notNull(values, "Form values are required!");
Assert.notNull(ownerEntity, "Form values owner is required!");
formDefinition = checkDefaultDefinition(ownerEntity.getClass(), formDefinition);
//
FormValueService<FormableEntity> formValueService = getFormValueService(ownerEntity);
//
Map<UUID, IdmFormValueDto> previousValues = new HashMap<>();
formValueService.getValues(ownerEntity, formDefinition).forEach(formValue -> {
previousValues.put(formValue.getId(), formValue);
});
//
List<IdmFormValueDto> results = new ArrayList<>();
for (IdmFormValueDto value : values) {
// value could contant attribute id only
UUID attributeId = value.getFormAttribute();
Assert.notNull(attributeId, "Form attribute is required");
IdmFormAttributeDto attribute = formDefinition.getMappedAttribute(attributeId);
Assert.notNull(attribute, "Form attribute is required");
//
value.setOwnerAndAttribute(ownerEntity, attribute);
//
IdmFormValueDto previousValue = value.getId() == null ? null : previousValues.get(value.getId());
if (previousValue != null) {
// saved values will not be removed
previousValues.remove(value.getId());
// confidential value is always updated - only new values are sent from client
if (value.isConfidential() || !value.isEquals(previousValue)) {
// update value
results.add(formValueService.save(value));
LOG.trace("FormValue [{}:{}] for owner [{}] was updated", attribute.getCode(), value.getId(), ownerEntity);
}
} else {
// create new value
results.add(formValueService.save(value));
LOG.trace("FormValue [{}:{}] for owner [{}] was created", attribute.getCode(), value.getId(), ownerEntity);
}
}
//
// remove unsaved values by attribute definition (patch method is not
// implemented now)
previousValues.values().stream().filter(formValue -> {
// they could not be sent with form (only changed values)
return !formValue.isConfidential();
}).forEach(value -> {
formValueService.delete(value);
LOG.trace("FormValue [{}:{}] for owner [{}] was deleted", value.getFormAttribute(), value.getId(), ownerEntity);
});
// publish event - eav was saved
if (lookupService.getDtoLookup(ownerEntity.getClass()) == null) {
// TODO: remove this branch after all agends will be rewritten to dto usage
entityEventManager.process(new CoreEvent<>(CoreEventType.EAV_SAVE, ownerEntity));
} else {
entityEventManager.process(new CoreEvent<>(CoreEventType.EAV_SAVE, lookupService.lookupDto(ownerEntity.getClass(), ownerEntity.getId())));
}
//
return new IdmFormInstanceDto(ownerEntity, formDefinition, results);
}
use of eu.bcvsolutions.idm.core.api.event.CoreEvent in project CzechIdMng by bcvsolutions.
the class AbstractSynchronizationExecutor method startReconciliation.
/**
* Start reconciliation. Is call after synchronization. Main purpose is find and
* resolve missing accounts
*
* @param entityType
* @param allAccountsSet
* @param config
* @param system
* @param log
* @param actionsLog
*/
protected void startReconciliation(SystemEntityType entityType, Set<String> allAccountsSet, AbstractSysSyncConfigDto config, SysSystemDto system, SysSyncLogDto log, List<SysSyncActionLogDto> actionsLog) {
if (!log.isRunning()) {
return;
}
AccAccountFilter accountFilter = new AccAccountFilter();
accountFilter.setSystemId(system.getId());
List<AccAccountDto> accounts = accountService.find(accountFilter, null).getContent();
for (AccAccountDto account : accounts) {
if (!log.isRunning()) {
return;
}
String uid = account.getRealUid();
if (!allAccountsSet.contains(uid)) {
SysSyncItemLogDto itemLog = new SysSyncItemLogDto();
try {
// Default setting for log item
itemLog.setIdentification(uid);
itemLog.setDisplayName(uid);
itemLog.setType(entityType.getEntityType().getSimpleName());
// Do reconciliation for one item (produces event)
// Start in new Transaction
SynchronizationContext builder = new SynchronizationContext();
builder.addUid(uid).addType(IcSyncDeltaTypeEnum.DELETE).addConfig(config).addSystem(system).addEntityType(entityType).addAccount(account).addLog(log).addLogItem(itemLog).addActionLogs(actionsLog);
CoreEvent<SysSyncItemLogDto> event = new CoreEvent<>(SynchronizationEventType.START_ITEM, itemLog);
event.getProperties().put(SynchronizationService.WRAPPER_SYNC_ITEM, builder);
EventResult<SysSyncItemLogDto> lastResult = entityEventManager.process(event).getLastResult();
boolean result = false;
if (lastResult != null && lastResult.getEvent().getProperties().containsKey(SynchronizationService.RESULT_SYNC_ITEM)) {
result = (boolean) lastResult.getEvent().getProperties().get(SynchronizationService.RESULT_SYNC_ITEM);
}
// Update (increased counter) and check state of sync (maybe was cancelled from
// sync or LRT)
updateAndCheckState(result, log);
} catch (Exception ex) {
String message = MessageFormat.format("Reconciliation - error for uid [{0}]", uid);
log.addToLog(message);
log.addToLog(Throwables.getStackTraceAsString(ex));
LOG.error(message, ex);
} finally {
config = synchronizationConfigService.save(config);
boolean existingItemLog = existItemLogInActions(actionsLog, itemLog);
actionsLog = saveActionLogs(actionsLog, log.getId());
//
if (!existingItemLog) {
addToItemLog(itemLog, MessageFormat.format("Missing action log for UID [{0}]!", uid));
initSyncActionLog(SynchronizationActionType.UNKNOWN, OperationResultType.ERROR, itemLog, log, actionsLog);
syncItemLogService.save(itemLog);
}
}
}
}
}
use of eu.bcvsolutions.idm.core.api.event.CoreEvent 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);
}
}
}
}
use of eu.bcvsolutions.idm.core.api.event.CoreEvent in project CzechIdMng by bcvsolutions.
the class AbstractSynchronizationExecutor method exportEntity.
/**
* Start export item (entity) to target resource
*
* @param context
* @param uidAttribute
* @param entity
*/
protected void exportEntity(SynchronizationContext context, SysSystemAttributeMappingDto uidAttribute, AbstractDto entity) {
SystemEntityType entityType = context.getEntityType();
AbstractSysSyncConfigDto config = context.getConfig();
SysSyncLogDto log = context.getLog();
List<SysSyncActionLogDto> actionsLog = context.getActionLogs();
SysSystemDto system = context.getSystem();
SysSyncItemLogDto itemLog = new SysSyncItemLogDto();
try {
// Default setting for log item
itemLog.setIdentification(entity.getId().toString());
itemLog.setDisplayName(this.getDisplayNameForEntity(entity));
itemLog.setType(entityType.getEntityType().getSimpleName());
itemLog.addToLog(MessageFormat.format("Start export for entity [{0}].", this.getDisplayNameForEntity(entity)));
UUID accountId = this.getAccountByEntity(entity.getId(), system.getId());
if (accountId != null) {
initSyncActionLog(SynchronizationActionType.CREATE_ACCOUNT, OperationResultType.IGNORE, itemLog, log, actionsLog);
itemLog.addToLog(MessageFormat.format("For entity [{0}] AccAccount [{1}] was found. Export for this entity ends (only entity without AccAccount can be exported)!", this.getDisplayNameForEntity(entity), accountId));
return;
}
String uid = systemAttributeMappingService.generateUid(entity, uidAttribute);
// Do export for one item (produces event)
// Start in new Transaction
//
context.addUid(uid).addConfig(//
config).addSystem(//
system).addEntityType(//
entityType).addEntityId(entity.getId()).addLog(//
log).addLogItem(//
itemLog).addActionLogs(//
actionsLog).addExportAction(true);
CoreEvent<SysSyncItemLogDto> event = new CoreEvent<>(SynchronizationEventType.START_ITEM, itemLog);
event.getProperties().put(SynchronizationService.WRAPPER_SYNC_ITEM, context);
EventResult<SysSyncItemLogDto> lastResult = entityEventManager.process(event).getLastResult();
boolean result = false;
if (lastResult != null && lastResult.getEvent().getProperties().containsKey(SynchronizationService.RESULT_SYNC_ITEM)) {
result = (boolean) lastResult.getEvent().getProperties().get(SynchronizationService.RESULT_SYNC_ITEM);
}
// Update (increased counter) and check state of sync (maybe was cancelled from
// sync or LRT)
updateAndCheckState(result, log);
} catch (Exception ex) {
String message = MessageFormat.format("Export - error for entity [{0}]", entity.getId());
log.addToLog(message);
log.addToLog(Throwables.getStackTraceAsString(ex));
LOG.error(message, ex);
} finally {
synchronizationConfigService.save(config);
boolean existingItemLog = existItemLogInActions(actionsLog, itemLog);
actionsLog = (List<SysSyncActionLogDto>) syncActionLogService.saveAll(actionsLog);
//
if (!existingItemLog) {
addToItemLog(itemLog, MessageFormat.format("Missing action log for entity [{0}]!", entity.getId()));
initSyncActionLog(SynchronizationActionType.UNKNOWN, OperationResultType.ERROR, itemLog, log, actionsLog);
syncItemLogService.save(itemLog);
}
}
}
use of eu.bcvsolutions.idm.core.api.event.CoreEvent in project CzechIdMng by bcvsolutions.
the class DefaultImportManager method executeImportForType.
/**
* Ensures add new and update existed DTOs by given batch.
*
* @param descriptor
* @param context
*/
private void executeImportForType(ExportDescriptorDto descriptor, ImportContext context) {
Class<? extends BaseDto> dtoClass = descriptor.getDtoClass();
Path dtoTypePath = Paths.get(context.getTempDirectory().toString(), dtoClass.getSimpleName());
try {
List<BaseDto> dtos;
try (Stream<Path> paths = Files.walk(dtoTypePath)) {
dtos = //
paths.filter(//
Files::isRegularFile).map(path -> {
BaseDto dto = convertFileToDto(path.toFile(), dtoClass, context);
Assert.notNull(dto, "DTO cannot be null after conversion from the batch!");
return dto;
}).collect(Collectors.toList());
}
if (dtos.isEmpty()) {
return;
}
// Sorts all DTOs for this type (maybe it is tree).
dtos = sortsDTOs(dtoClass, dtos);
int i = 0;
for (BaseDto dto : dtos) {
// Flush Hibernate in batch - performance improving
if (i % 20 == 0 && i > 0) {
// Call hard hibernate session flush and clear
if (getHibernateSession().isOpen()) {
getHibernateSession().flush();
getHibernateSession().clear();
}
}
i++;
// Increase counter and update state of import LRT.
context.getImportTaskExecutor().increaseCounter();
context.getImportTaskExecutor().updateState();
BaseDto parentDto = getParentDtoFromBatch(dto, context);
if (parentDto == null) {
parentDto = dto;
}
BaseDto originalDto = dto;
try {
dto = makeAdvancedPairing(dto, context, dtoClass);
if (dto == null) {
// If DTO after advanced pairing is null, then was not found and is optional ->
// skip.
IdmImportLogDto dtoLog = new IdmImportLogDto(context.getBatch(), originalDto, RequestOperationType.ADD, (UUID) parentDto.getId());
ResultModel resultModel = new DefaultResultModel(CoreResultCode.IMPORT_DTO_SKIPPED, ImmutableMap.of("dto", originalDto.toString()));
dtoLog.setResult(new OperationResultDto.Builder(OperationState.CANCELED).setModel(resultModel).build());
importLogService.saveDistinct(dtoLog);
continue;
}
} catch (ResultCodeException ex) {
if (context.isDryRun() && ex.getError() != null && ex.getError().getError() != null && CoreResultCode.IMPORT_ADVANCED_PARING_FAILED_NOT_FOUND.name().equals(ex.getError().getError().getStatusEnum())) {
// Not found DTO we will mark as skipped in dry run mode.
IdmImportLogDto dtoLog = new IdmImportLogDto(context.getBatch(), originalDto, RequestOperationType.ADD, (UUID) parentDto.getId());
dtoLog.setResult(new OperationResultDto.Builder(OperationState.EXCEPTION).setException(ex).build());
importLogService.saveDistinct(dtoLog);
continue;
} else if (ex.getError() != null && ex.getError().getError() != null && CoreResultCode.IMPORT_ADVANCED_PARING_NOT_FOUND_OPTIONAL.name().equals(ex.getError().getError().getStatusEnum())) {
// Not found DTO, but optional, we will mark as skipped.
IdmImportLogDto dtoLog = new IdmImportLogDto(context.getBatch(), originalDto, RequestOperationType.ADD, (UUID) parentDto.getId());
dtoLog.setResult(new OperationResultDto.Builder(OperationState.CANCELED).setException(ex).build());
importLogService.saveDistinct(dtoLog);
continue;
}
throw ex;
}
Class<? extends BaseDto> serviceDtoClass = dtoClass;
if (dto instanceof IdmFormInstanceDto) {
// Form instance is very special here (doesn't have entity in DB).
IdmFormInstanceDto formInstance = (IdmFormInstanceDto) dto;
IdmFormDefinitionDto definition = formInstance.getFormDefinition();
Assert.notNull(definition, "Definition cannot be null for import!");
CoreEvent<IdmFormInstanceDto> event = new CoreEvent<>(CoreEventType.UPDATE, formInstance);
// Check if owner exist (UPDATE/ADD)
@SuppressWarnings("unchecked") Class<? extends BaseDto> ownerType = (Class<? extends BaseDto>) ((IdmFormInstanceDto) dto).getOwnerType();
UUID ownerId = UUID.fromString((String) ((IdmFormInstanceDto) dto).getOwnerId());
BaseDto ownerDto = this.getDtoService(ownerType).get(ownerId);
IdmImportLogDto dtoLog = new IdmImportLogDto(context.getBatch(), dto, ownerDto != null ? RequestOperationType.UPDATE : RequestOperationType.ADD, ownerId);
if (!context.isDryRun()) {
formService.publish(event);
dtoLog.setResult(new OperationResultDto(OperationState.EXECUTED));
} else {
dtoLog.setResult(new OperationResultDto.Builder(OperationState.NOT_EXECUTED).setModel(//
new DefaultResultModel(CoreResultCode.IMPORT_EXECUTED_AS_DRYRUN)).build());
}
importLogService.saveDistinct(dtoLog);
continue;
}
if (dto.getClass().isAnnotationPresent(Inheritable.class)) {
serviceDtoClass = dto.getClass().getAnnotation(Inheritable.class).dtoService();
}
ReadWriteDtoService<BaseDto, ?> dtoService = getDtoService(serviceDtoClass);
BaseDto currentDto = dtoService.get(dto.getId());
if (currentDto != null) {
// DTO with same ID already exists -> update.
IdmImportLogDto dtoLog = new IdmImportLogDto(context.getBatch(), dto, RequestOperationType.UPDATE, (UUID) parentDto.getId());
// Resolve excluded fields
dto = this.excludeFields(dto, currentDto, context);
if (!context.isDryRun()) {
dtoService.save(dto);
dtoLog.setResult(new OperationResultDto(OperationState.EXECUTED));
} else {
dtoLog.setResult(new OperationResultDto.Builder(OperationState.NOT_EXECUTED).setModel(//
new DefaultResultModel(CoreResultCode.IMPORT_EXECUTED_AS_DRYRUN)).build());
}
importLogService.saveDistinct(dtoLog);
continue;
}
if (dto instanceof Codeable) {
// We try to find exists DTO by code.
currentDto = lookupService.lookupDto(serviceDtoClass, ((Codeable) dto).getCode());
}
// Find target DTO by example source DTO (typically by more then one filter field).
currentDto = findByExample(dto, null, context);
if (dto instanceof IdmFormDefinitionDto) {
IdmFormDefinitionDto definition = (IdmFormDefinitionDto) dto;
// We try to find exists definition by code and type (IdmFormDefinitionDto is
// not Codeable).
currentDto = formService.getDefinition(definition.getType(), definition.getCode());
}
if (dto instanceof IdmFormAttributeDto) {
IdmFormAttributeDto attribute = (IdmFormAttributeDto) dto;
IdmFormDefinitionDto definition = formService.getDefinition(attribute.getFormDefinition());
if (definition != null) {
// We try to find exists attribute definition by code and form definition.
currentDto = formService.getAttribute(definition, attribute.getCode());
} else {
currentDto = null;
}
}
if (currentDto != null) {
// We found current DTO in IdM.
// Save old and new ID for next DTOs.
context.getReplacedIDs().put((UUID) dto.getId(), (UUID) currentDto.getId());
// We have to change the ID in import DTO.
dto.setId(currentDto.getId());
// Update current DTO by batch DTO.
IdmImportLogDto dtoLog = new IdmImportLogDto(context.getBatch(), dto, RequestOperationType.UPDATE, (UUID) parentDto.getId());
if (!context.isDryRun()) {
// Resolve excluded fields
dto = this.excludeFields(dto, currentDto, context);
// Save a DTO.
dtoService.save(dto);
dtoLog.setResult(new OperationResultDto(OperationState.EXECUTED));
} else {
dtoLog.setResult(new OperationResultDto.Builder(OperationState.NOT_EXECUTED).setModel(//
new DefaultResultModel(CoreResultCode.IMPORT_EXECUTED_AS_DRYRUN)).build());
}
importLogService.saveDistinct(dtoLog);
} else {
IdmImportLogDto dtoLog = new IdmImportLogDto(context.getBatch(), dto, RequestOperationType.ADD, (UUID) parentDto.getId());
// No current DTO was found -> create.
if (!context.isDryRun()) {
// Resolve excluded fields
dto = this.excludeFields(dto, null, context);
// Save new DTO.
dtoService.save(dto);
dtoLog.setResult(new OperationResultDto(OperationState.EXECUTED));
} else {
dtoLog.setResult(new OperationResultDto.Builder(OperationState.NOT_EXECUTED).setModel(//
new DefaultResultModel(CoreResultCode.IMPORT_EXECUTED_AS_DRYRUN)).build());
}
importLogService.saveDistinct(dtoLog);
}
}
} catch (IOException | IllegalArgumentException e) {
throw new ResultCodeException(CoreResultCode.EXPORT_IMPORT_IO_FAILED, e);
}
}
Aggregations