use of eu.bcvsolutions.idm.core.api.dto.DefaultResultModel in project CzechIdMng by bcvsolutions.
the class DefaultEntityEventManager method executeEvent.
@Override
@Transactional
public void executeEvent(IdmEntityEventDto event) {
Assert.notNull(event, "Event is reqired to be event executed.");
Assert.notNull(event.getOwnerId(), "Event owner identifier is reqired to be event executed.");
if (!eventConfiguration.isAsynchronous()) {
// synchronous processing
// we don't persist events and their states
process(new CoreEvent<>(EntityEventType.EXECUTE, event));
return;
}
if (event.getPriority() == PriorityType.IMMEDIATE) {
// synchronous processing
// we don't persist events and their states
// TODO: what about running event with the same owner? And events in queue for the same owner => no locking now, last wins
process(new CoreEvent<>(EntityEventType.EXECUTE, event));
return;
}
//
if (runningOwnerEvents.putIfAbsent(event.getOwnerId(), event.getId()) != null) {
LOG.debug("Previous event [{}] for owner with id [{}] is currently processed.", runningOwnerEvents.get(event.getOwnerId()), event.getOwnerId());
// event will be processed in another scheduling
return;
}
// check super owner is not processed
UUID superOwnerId = event.getSuperOwnerId();
if (superOwnerId != null && !superOwnerId.equals(event.getOwnerId())) {
if (runningOwnerEvents.putIfAbsent(superOwnerId, event.getId()) != null) {
LOG.debug("Previous event [{}] for super owner with id [{}] is currently processed.", runningOwnerEvents.get(superOwnerId), superOwnerId);
runningOwnerEvents.remove(event.getOwnerId());
// event will be processed in another scheduling
return;
}
}
// execute event in new thread asynchronously
try {
eventConfiguration.getExecutor().execute(new Runnable() {
@Override
@SuppressWarnings("unchecked")
public void run() {
// run as event creator
securityService.setAuthentication(new IdmJwtAuthentication(new IdmIdentityDto(event.getCreatorId(), event.getCreator()), new IdmIdentityDto(event.getOriginalCreatorId(), event.getOriginalCreator()), null, ZonedDateTime.now(), Lists.newArrayList(IdmAuthorityUtils.getAdminAuthority()), null));
// run under original transaction id - asynchronous processing continue the "user" transaction
TransactionContextHolder.setContext(new TransactionContext(event.getTransactionId()));
//
LOG.debug("Executing event under user [{}] (admin authorities) and transaction [{}]", securityService.getUsername(), TransactionContextHolder.getContext().getTransactionId());
//
try {
process(new CoreEvent<>(EntityEventType.EXECUTE, event));
} catch (Exception ex) {
// all processor should persist their own entity state (see AbstractEntityEventProcessor)
// event result is persisted here
OperationState resultState = OperationState.EXCEPTION;
ResultModel resultModel;
if (ex instanceof ResultCodeException) {
ResultCodeException resultCodeException = (ResultCodeException) ex;
resultModel = resultCodeException.getError().getError();
if (resultCodeException.getStatus() == HttpStatus.ACCEPTED) {
// => concrete information is preserved in model to know, what happen
resultState = OperationState.EXECUTED;
}
} else {
resultModel = new DefaultResultModel(CoreResultCode.EVENT_EXECUTE_FAILED, ImmutableMap.of("eventId", event.getId(), "eventType", String.valueOf(event.getEventType()), "ownerId", String.valueOf(event.getOwnerId()), "instanceId", String.valueOf(event.getInstanceId())));
}
saveResult(event.getId(), new OperationResultDto.Builder(resultState).setCause(ex).setModel(resultModel).build());
//
ExceptionUtils.log(LOG, resultModel, ex);
// We check if owner service supports this feature (implements ExceptionProcessable).
try {
Class<?> ownerClass = Class.forName(event.getOwnerType());
ReadDtoService<?, ?> dtoService = lookupService.getDtoService((Class<? extends Identifiable>) ownerClass);
if (dtoService instanceof ExceptionProcessable) {
ExceptionProcessable<?> exceptionProcessable = (ExceptionProcessable<?>) dtoService;
// Propagate the exception
exceptionProcessable.processException(event.getOwnerId(), ex);
}
} catch (ClassNotFoundException e) {
// Only to the log
LOG.error(e.getLocalizedMessage(), e);
}
} finally {
LOG.trace("Event [{}] ends for owner with id [{}].", event.getId(), event.getOwnerId());
removeRunningEvent(event);
}
}
});
//
LOG.trace("Running event [{}] for owner with id [{}].", event.getId(), event.getOwnerId());
} catch (RejectedExecutionException ex) {
// thread pool queue is full - wait for another try
removeRunningEvent(event);
}
}
use of eu.bcvsolutions.idm.core.api.dto.DefaultResultModel in project CzechIdMng by bcvsolutions.
the class DefaultEntityEventManager method getCreatedEvents.
/**
* Called from scheduler - concurrency is prevented.
* Returns events to process sorted by priority 7 / 3 (high / normal).
* Immediate priority is executed synchronously.
* Cancel duplicate events (same type, owner and props) - last event is returned
*
* @param instanceId
* @return
*/
protected List<IdmEntityEventDto> getCreatedEvents(String instanceId) {
Assert.notNull(instanceId, "Server instance identifier is required.");
//
// already running owners are excluded (super owner is excluded too)
List<UUID> exceptOwnerIds = Lists.newArrayList(runningOwnerEvents.keySet());
// prevent sql queue size is exceeded
exceptOwnerIds = exceptOwnerIds.subList(0, exceptOwnerIds.size() > 500 ? 500 : exceptOwnerIds.size());
//
// load created events - high priority
ZonedDateTime executeDate = ZonedDateTime.now();
Page<IdmEntityEventDto> highEvents = entityEventService.findToExecute(instanceId, executeDate, PriorityType.HIGH, exceptOwnerIds, PageRequest.of(0, eventConfiguration.getBatchSize(), new Sort(Direction.ASC, Auditable.PROPERTY_CREATED)));
// load created events - low priority
Page<IdmEntityEventDto> normalEvents = entityEventService.findToExecute(instanceId, executeDate, PriorityType.NORMAL, exceptOwnerIds, PageRequest.of(0, eventConfiguration.getBatchSize(), new Sort(Direction.ASC, Auditable.PROPERTY_CREATED)));
// merge events
List<IdmEntityEventDto> events = new ArrayList<>();
events.addAll(highEvents.getContent());
events.addAll(normalEvents.getContent());
// sort by created date
events.sort(new CreatedComparator());
//
// cancel duplicates - by owner => properties has to be the same
// execute the first event for each owner only - preserve events order
Map<UUID, IdmEntityEventDto> distinctEvents = new LinkedHashMap<>();
events.forEach(event -> {
if (!distinctEvents.containsKey(event.getOwnerId())) {
// the first event
distinctEvents.put(event.getOwnerId(), event);
} else {
// cancel duplicate older event
IdmEntityEventDto olderEvent = distinctEvents.get(event.getOwnerId());
if (isDuplicate(olderEvent, event)) {
// try to set higher priority
if (olderEvent.getPriority() == PriorityType.HIGH) {
event.setPriority(PriorityType.HIGH);
}
distinctEvents.put(event.getOwnerId(), event);
//
LOG.debug(new DefaultResultModel(CoreResultCode.EVENT_DUPLICATE_CANCELED, ImmutableMap.of("eventId", olderEvent.getId(), "eventType", String.valueOf(olderEvent.getEventType()), "ownerId", String.valueOf(olderEvent.getOwnerId()), "instanceId", String.valueOf(olderEvent.getInstanceId()), "neverEventId", event.getId())).toString());
//
IdmEntityEventFilter eventFilter = new IdmEntityEventFilter();
eventFilter.setParentId(olderEvent.getId());
if (entityEventService.find(eventFilter, PageRequest.of(0, 1)).getTotalElements() == 0) {
deleteEvent(olderEvent);
}
}
}
});
//
// sort by priority
events = distinctEvents.values().stream().sorted((o1, o2) -> {
return Integer.compare(o1.getPriority().getPriority(), o2.getPriority().getPriority());
}).collect(Collectors.toList());
int normalCount = events.stream().filter(e -> e.getPriority() == PriorityType.NORMAL).collect(Collectors.toList()).size();
int maxNormalCount = eventConfiguration.getBatchSize() / 3;
int highMaximum = normalCount > maxNormalCount ? (eventConfiguration.getBatchSize() - maxNormalCount) : (eventConfiguration.getBatchSize() - normalCount);
// evaluate priority => high 70 / low 30
int highCounter = 0;
List<IdmEntityEventDto> prioritizedEvents = new ArrayList<>();
for (IdmEntityEventDto event : events) {
if (event.getPriority() == PriorityType.HIGH) {
if (highCounter < highMaximum) {
prioritizedEvents.add(event);
highCounter++;
}
} else {
// normal priority remains only
if (prioritizedEvents.size() >= eventConfiguration.getBatchSize()) {
break;
}
prioritizedEvents.add(event);
}
}
//
return prioritizedEvents;
}
use of eu.bcvsolutions.idm.core.api.dto.DefaultResultModel in project CzechIdMng by bcvsolutions.
the class ProcessSkippedAutomaticRoleByTreeTaskExecutor method processItem.
@Override
public Optional<OperationResult> processItem(IdmEntityStateDto state) {
// check state is already processed by ProcessAutomaticRoleByTreeTaskExecutor
// => automatic role recount can be skipped multiple times for the same automatic role.
UUID ownerId = state.getOwnerId();
state = entityStateService.get(state);
if (state == null) {
LOG.debug("Automatic roles for owner [{}] was already processed.", ownerId);
// we need some result - counter / count will match.
return Optional.of(new OperationResult.Builder(OperationState.EXECUTED).build());
}
//
if (processedOwnerIds.contains(ownerId)) {
LOG.debug("Automatic roles for owner [{}] was already processed, delete state only.", ownerId);
//
entityStateManager.deleteState(state);
// Item will be deleted only - we need some result - counter / count will match.
return Optional.of(new OperationResult.Builder(OperationState.EXECUTED).build());
}
//
// process automatic role on state owner
LOG.debug("Process automatic roles for contract [{}].", ownerId);
//
IdmRoleTreeNodeDto automaticRole = lookupService.lookupDto(IdmRoleTreeNodeDto.class, ownerId);
if (automaticRole == null) {
getItemService().createLogItem(state, new OperationResult.Builder(OperationState.NOT_EXECUTED).setModel(new DefaultResultModel(CoreResultCode.CONTENT_DELETED, ImmutableMap.of("ownerId", ownerId, "ownerType", entityEventManager.getOwnerType(IdmRoleTreeNodeDto.class)))).build(), this.getLongRunningTaskId());
// delete state only
entityStateManager.deleteState(state);
} else {
ProcessAutomaticRoleByTreeTaskExecutor automaticRoleTask = AutowireHelper.createBean(ProcessAutomaticRoleByTreeTaskExecutor.class);
automaticRoleTask.setAutomaticRoles(Lists.newArrayList(automaticRole.getId()));
// invalid roles will be removed, after LRT end (prevent drop and create target account)
automaticRoleTask.setRemoveNotProcessedIdentityRoles(false);
automaticRoleTask.setRequireNewTransaction(true);
// exception is thrown and logged otherwise
longRunningTaskManager.executeSync(automaticRoleTask);
processedRoleRequests.addAll(automaticRoleTask.getProcessedRoleRequests());
processedAutomaticRoles.add(ownerId);
//
getItemService().createLogItem(automaticRole, new OperationResult.Builder(OperationState.EXECUTED).build(), this.getLongRunningTaskId());
}
//
processedOwnerIds.add(ownerId);
// Log added manually above - log processed contract / position instead of deleted entity state.
return Optional.empty();
}
use of eu.bcvsolutions.idm.core.api.dto.DefaultResultModel in project CzechIdMng by bcvsolutions.
the class RemoveRoleCompositionTaskExecutor method processItem.
@Override
public Optional<OperationResult> processItem(IdmIdentityRoleDto identityRole) {
try {
// create request
IdmIdentityContractDto contract = DtoUtils.getEmbedded(identityRole, IdmIdentityRole_.identityContract);
UUID identityId = contract.getIdentity();
IdmRoleRequestDto roleRequest = new IdmRoleRequestDto();
roleRequest.setState(RoleRequestState.CONCEPT);
// without approval
roleRequest.setExecuteImmediately(true);
roleRequest.setApplicant(identityId);
roleRequest.setRequestedByType(RoleRequestedByType.AUTOMATICALLY);
roleRequest = roleRequestService.save(roleRequest);
// create concepts
createConcepts(roleRequest, new ArrayList<>(), identityRole);
// start event with skip check authorities
RoleRequestEvent requestEvent = new RoleRequestEvent(RoleRequestEventType.EXCECUTE, roleRequest);
requestEvent.getProperties().put(IdmIdentityRoleService.SKIP_CHECK_AUTHORITIES, Boolean.TRUE);
// prevent to start asynchronous event before previous update event is completed.
requestEvent.setSuperOwnerId(identityId);
//
roleRequestService.startRequestInternal(requestEvent);
//
return Optional.of(new OperationResult.Builder(OperationState.EXECUTED).build());
} catch (Exception ex) {
return Optional.of(new OperationResult.Builder(OperationState.EXCEPTION).setModel(new DefaultResultModel(CoreResultCode.ROLE_COMPOSITION_ASSIGNED_ROLE_REMOVAL_FAILED, ImmutableMap.of("identityRole", identityRole.getId().toString()))).setCause(ex).build());
}
}
use of eu.bcvsolutions.idm.core.api.dto.DefaultResultModel in project CzechIdMng by bcvsolutions.
the class PasswordExpiredTaskExecutor method processItem.
@Override
public Optional<OperationResult> processItem(IdmPasswordDto dto) {
if (!expiration.isAfter(dto.getValidTill())) {
// skip the same date (valid till filter <=) - just info into lrt. Will be processed next day.
return Optional.of(new OperationResult.Builder(OperationState.NOT_EXECUTED).setModel(new DefaultResultModel(CoreResultCode.PASSWORD_EXPIRATION_TODAY_INFO)).build());
}
//
IdmIdentityDto identity = getLookupService().lookupEmbeddedDto(dto, IdmPassword_.identity);
LOG.info("Publishing [{}] event to identity [{}], password expired in [{}]", IdentityEventType.PASSWORD_EXPIRED, identity.getUsername(), dto.getValidTill());
try {
entityEventManager.process(new IdentityEvent(IdentityEventType.PASSWORD_EXPIRED, identity));
return Optional.of(new OperationResult.Builder(OperationState.EXECUTED).build());
} catch (Exception ex) {
LOG.error("Publishing [{}] event to identity [{}], password expired in [{}] failed", IdentityEventType.PASSWORD_EXPIRED, dto.getIdentity(), dto.getValidTill(), ex);
return Optional.of(new OperationResult.Builder(OperationState.EXCEPTION).setCause(ex).build());
}
}
Aggregations