use of eu.bcvsolutions.idm.core.api.event.CoreEvent in project CzechIdMng by bcvsolutions.
the class DefaultEntityEventManagerIntergationTest method testBaseDtoProcessing.
@Test
public void testBaseDtoProcessing() {
MockDto mockDto = new MockDto();
ObserveDtoProcessor.listenContent(mockDto.getId());
CoreEvent<BaseDto> event = new CoreEvent<BaseDto>(CoreEventType.NOTIFY, mockDto);
EventContext<BaseDto> processed = manager.process(event);
Assert.assertNotNull(processed.getLastResult());
Boolean observed = (Boolean) processed.getLastResult().getEvent().getProperties().get(ObserveDtoProcessor.PROPERTY_OBSERVED);
//
Assert.assertNotNull(observed);
Assert.assertTrue(observed);
}
use of eu.bcvsolutions.idm.core.api.event.CoreEvent in project CzechIdMng by bcvsolutions.
the class DefaultFormService method saveFormInstance.
/**
* {@inheritDoc}
*
* Only given form attributes by the given values will be saved. Other attributes will be left untouched.
*
* 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> newValues, boolean validate, BasePermission... permission) {
FormableEntity ownerEntity = getOwnerEntity(owner);
Assert.notNull(ownerEntity, "Form values owner is required.");
formDefinition = checkDefaultDefinition(ownerEntity.getClass(), formDefinition);
IdmFormInstanceDto formInstance = new IdmFormInstanceDto(ownerEntity, formDefinition, newValues);
//
CoreEvent<IdmFormInstanceDto> event = new CoreEvent<>(CoreEventType.UPDATE, formInstance);
// check permissions - check access to filled form values
event.setPermission(permission);
// Skip of validation.
event.getProperties().put(SKIP_EAV_VALIDATION, !validate);
// publish event for save form instance - see {@link #saveFormInstance(EntityEvent<IdmFormInstanceDto>)}
return entityEventManager.process(event).getContent();
}
use of eu.bcvsolutions.idm.core.api.event.CoreEvent in project CzechIdMng by bcvsolutions.
the class IdmFormDefinitionController method saveFormValues.
/**
* Saves owner's form values.
*
* @param owner
* @param formDefinition
* @param formValues
* @param permission base permissions to evaluate (AND)
* @return
* @throws ForbiddenEntityException if authorization policies doesn't met
*/
public Resource<?> saveFormValues(Identifiable owner, IdmFormDefinitionDto formDefinition, List<IdmFormValueDto> formValues, BasePermission... permission) {
formDefinition = getDefinition(owner.getClass(), formDefinition);
// construct form instance with given values
IdmFormInstanceDto formInstance = new IdmFormInstanceDto(owner, formDefinition, formValues);
// prepare event envelope
CoreEvent<IdmFormInstanceDto> event = new CoreEvent<>(CoreEventType.UPDATE, formInstance);
// FE - high event priority
event.setPriority(PriorityType.HIGH);
// publish event for save form instance
return new Resource<>(formService.publish(event, permission).getContent());
}
use of eu.bcvsolutions.idm.core.api.event.CoreEvent in project CzechIdMng by bcvsolutions.
the class DefaultEntityEventManager method process.
@Override
@Transactional
@SuppressWarnings("unchecked")
public <E extends Serializable> EventContext<E> process(EntityEvent<E> event, EntityEvent<?> parentEvent) {
Assert.notNull(event, "Event is required for processing.");
Serializable content = event.getContent();
//
LOG.info("Publishing event [{}]", event);
//
// continue suspended event
event.getContext().setSuspended(false);
//
if (parentEvent != null) {
event.setParentId(parentEvent.getId());
event.setRootId(parentEvent.getRootId() == null ? parentEvent.getId() : parentEvent.getRootId());
if (parentEvent.getPriority() != null && (event.getPriority() == null || event.getPriority().getPriority() < parentEvent.getPriority().getPriority())) {
// parent has higher priority ... execute with the same priority as parent
event.setPriority(parentEvent.getPriority());
}
// parent event type can be preset manually
if (StringUtils.isEmpty(event.getParentType())) {
event.setParentType(parentEvent.getType().name());
}
// propagate properties from parent to child event.
// properties need for internal event processing are ignored (see {@link EntityEvent} properties)
propagateProperties(event, parentEvent);
}
// read previous (original) dto source - usable in "check modification" processors
if (event.getOriginalSource() == null && (content instanceof AbstractDto)) {
// original source could be set externally
AbstractDto contentDto = (AbstractDto) content;
// works only for dto modification
if (contentDto.getId() != null && lookupService.getDtoLookup(contentDto.getClass()) != null) {
event.setOriginalSource((E) lookupService.lookupDto(contentDto.getClass(), contentDto.getId()));
}
}
// event is persisted automatically, when parent event is persisted
try {
if (content instanceof BaseDto && event.getId() == null && event.getParentId() != null && lookupService.getEntityClass(((BaseDto) content).getClass()) != null) {
// entity event can be persisted into queue only
BaseDto dto = (BaseDto) content;
if (dto.getId() == null) {
// prepare id for new content - event is persisted before entity is persisted.
dto.setId(UUID.randomUUID());
}
//
IdmEntityEventDto preparedEvent = toDto(dto, (EntityEvent<AbstractDto>) event);
// RUNNING => prevent to start by async task
preparedEvent.setResult(new OperationResultDto.Builder(OperationState.RUNNING).build());
preparedEvent.setRootId(event.getRootId() == null ? event.getParentId() : event.getRootId());
preparedEvent = entityEventService.save(preparedEvent);
event.setId(preparedEvent.getId());
//
// prepared event is be executed
CoreEvent<IdmEntityEventDto> executeEvent = new CoreEvent<>(EntityEventType.EXECUTE, preparedEvent);
publisher.publishEvent(executeEvent);
//
// fill original event result
E processedContent = (E) preparedEvent.getContent();
if (processedContent != null) {
event.setContent(processedContent);
}
event.getContext().addResult(new DefaultEventResult<E>(event, new EmptyEntityEventProcessor<E>()));
//
return completeEvent(event);
} else {
publisher.publishEvent(event);
//
return completeEvent(event);
}
} catch (Exception ex) {
completeEvent(event);
//
throw ex;
}
}
use of eu.bcvsolutions.idm.core.api.event.CoreEvent 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);
}
}
Aggregations