Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision Next revision Both sides next revision | ||
devel:documentation:architecture:dev:events [2018/09/25 12:06] tomiskar [ContractPositionAutomaticRoleProcessor] |
devel:documentation:architecture:dev:events [2020/08/13 07:35] tomiskar [AsyncEntityEventProcessor] |
||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Events - processing of events ====== | ||
+ | |||
+ | {{tag> event architecture configuration processor}} | ||
+ | |||
+ | An event mechanism has been designed to make extending and overlapping of the CzechIdM core functionality within any module possible. | ||
+ | |||
+ | The event ('' | ||
+ | |||
+ | ===== Event lifecycle ===== | ||
+ | |||
+ | - Event is created with given content | ||
+ | |||
+ | <code java> | ||
+ | EntityEvent< | ||
+ | </ | ||
+ | |||
+ | - then is given to the processing via '' | ||
+ | |||
+ | <code java> | ||
+ | EventContext< | ||
+ | </ | ||
+ | |||
+ | - when event is published and their content is descendant of '' | ||
+ | - returning context contains results from all reacting processors in defined processors order. | ||
+ | - the processor can label the event as ('' | ||
+ | - when event walk through processors, then event' | ||
+ | |||
+ | ===== Event types ===== | ||
+ | |||
+ | Event is published with content and specific event type (e.g. '' | ||
+ | |||
+ | **Event types has to be compared by their string representation, | ||
+ | |||
+ | <code java> | ||
+ | ... | ||
+ | EntityEvent< | ||
+ | if (event.hasType(IdentityEventType.CREATE)) { | ||
+ | // do something | ||
+ | } | ||
+ | ... | ||
+ | </ | ||
+ | |||
+ | Module can publish their own event types. Basic (core) event types | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | Different (and custom) event types can be used for different entities. | ||
+ | |||
+ | ===== Entities with event support ===== | ||
+ | |||
+ | Supported events for individual entities: | ||
+ | * '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * adds event type '' | ||
+ | * adds event type '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * event is propagated when identity log in (e.g. last login date is changed) | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * event is propagated when token is created, disabled (=> updated), deleted - e.g. when identity log in / out (token type '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * adds event type '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * adds event type '' | ||
+ | * supports event type '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * adds event type '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * supports base event type '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * adds event type '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * adds event type '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * adds event type '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * adds event type '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * supports base event types '' | ||
+ | * '' | ||
+ | * adds event type '' | ||
+ | * adds event type '' | ||
+ | * adds event type '' | ||
+ | * adds event type '' | ||
+ | * '' | ||
+ | * adds event type '' | ||
+ | * adds event type '' | ||
+ | * adds event type '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * adds event type '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * adds event type '' | ||
+ | |||
+ | |||
+ | A page has been created directly in the application on the module page for an overview of all entity types and event types migrating through event processing. All the registered processors including the configuration are listed there: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | |||
+ | The default order for listeners ('' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | ===== Basic interfaces ===== | ||
+ | |||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | ===== Basic classes ===== | ||
+ | |||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | ==== AbstractEntityEventProcessor ==== | ||
+ | Use this super class, when creating new processor implementation (this class contains some boring parts). | ||
+ | |||
+ | Methods, which have to be implemented: | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | Methods, which could be implemented [optional]: | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | ==== AsyncEntityEventProcessor ==== | ||
+ | |||
+ | Use this super class, when creating new asynchronous processor implementation. | ||
+ | |||
+ | Methods, which could be implemented [optional]: | ||
+ | |||
+ | * '' | ||
+ | |||
+ | ==== AbstractInitApplicationProcessor==== | ||
+ | |||
+ | Use this super class for providing application and module [[todo|init data]]. | ||
+ | |||
+ | |||
+ | |||
+ | ===== Transactions ===== | ||
+ | |||
+ | Transactional processing is controlled before the event publishing itself - the whole processing now takes place in a one transaction and all processors run synchronously by default. In case of an error in any processor, the whole transaction is rolled back, which has some advantages: | ||
+ | * simple adding of validation or referential integrity | ||
+ | * repeating the whole chain | ||
+ | and disadvantages as well: | ||
+ | * having to catch all the exceptions properly to avoid " | ||
+ | * saving logs and archives in the new transaction ('' | ||
+ | |||
+ | ===== Event properties ===== | ||
+ | |||
+ | Event properties ('' | ||
+ | |||
+ | Event properties are propagated automatically from parent into child event: | ||
+ | * if parent event is given, when child event is published | ||
+ | * if child event doesn' | ||
+ | * properties needed for internal event mechanism are not propagated. Property keys can be found in '' | ||
+ | |||
+ | <note tip>When '' | ||
+ | ===== Asynchronous event processing ===== | ||
+ | |||
+ | CzechIdM 8.0.0 brings new feature - asynchronous event processing. New event type '' | ||
+ | |||
+ | Asynchronous '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | <note important> | ||
+ | |||
+ | Other entities will be added soon, when new asynchronous entity event processors will be implemented. | ||
+ | |||
+ | '' | ||
+ | * order **500** - by automatic roles in core module, | ||
+ | * order **1000** - by account management in acc module, then provisioning is executed. | ||
+ | |||
+ | When asynchronous event is published, it's persisted into event queue ('' | ||
+ | |||
+ | ==== Features ==== | ||
+ | |||
+ | === Process event from queue === | ||
+ | |||
+ | Events from queue are processed by event owner id - one event for one owner can be executed in the same time => we need to preserven event order by created date for one owner. Super owner id ('' | ||
+ | |||
+ | <note important> | ||
+ | |||
+ | === Event priority === | ||
+ | |||
+ | Before event is persisted into queue, then event priority is evaluated, priority types: | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | Events are processed from queue by internal scheduled tasks by priority. Events with '' | ||
+ | |||
+ | Priority can be set to event manually or registered processors can vote about event' | ||
+ | |||
+ | === Execute date === | ||
+ | |||
+ | Execute date can be set to event manually. Event with priority '' | ||
+ | |||
+ | === Parent event === | ||
+ | |||
+ | Event can be published by another event ~ event chain (tree) is persisted. For example, when contract is saved, then contract '' | ||
+ | |||
+ | === Event parameters === | ||
+ | |||
+ | When asynchronous event is published, then event content (and previous ~ original content) and event parameters is persisted into queue. This persisted attributes are used, when event is resurrected from queue and executed. Attributes are available in registered asynchronous processors - evaluate modifications, | ||
+ | |||
+ | === Remove duplicate events === | ||
+ | |||
+ | When internal scheduled task for executing event from queue is processed, then duplicate events are removed. | ||
+ | |||
+ | Duplicate event is event with the same: | ||
+ | * owner | ||
+ | * event type | ||
+ | * event properties | ||
+ | * original source (embedded dtos and audit fields are ignored). | ||
+ | |||
+ | Older duplicate events are removed - the newest event is used. Events are processed by priority in batch, default batch size can be [[..: | ||
+ | |||
+ | === Entity state === | ||
+ | |||
+ | Persist event (~entity) state, when event is processed. State can be persisted manually, even without event processing. This state will be shown on entity detail soon (new frontend component). | ||
+ | |||
+ | === Notification === | ||
+ | |||
+ | Notification about registered asynchronous processors is prepared, when asynchronous event is published. Notification is send into topic '' | ||
+ | |||
+ | ==== Configuration ==== | ||
+ | |||
+ | * [[..: | ||
+ | * [[..: | ||
+ | * [[# | ||
+ | |||
+ | ===== Predefined processors order ===== | ||
+ | |||
+ | * **0** - basic / core functionality - operation '' | ||
+ | * **50** - save eav, which are send together with owner' | ||
+ | * **100** - automatic roles computation. | ||
+ | * **1000** - after '' | ||
+ | * **10000** - publish '' | ||
+ | * **-1000** - before '' | ||
+ | * **Identity**: | ||
+ | * **-2000** - validate password in acc module - checks all system password policies and idm default policy => all policies are evaluated in one request. If acc module is enabled, then core password validation processor can be disabled. | ||
+ | * **-1000** - validate password in core module - checks idm default policy. | ||
+ | * **100** - persist password | ||
+ | * **Contract**: | ||
+ | * **100** - Automatic roles recount while identity contract is saved, updated or deleted / disabled. | ||
+ | * **200** - Contract [[..: | ||
+ | * **LongRunningTask**: | ||
+ | * **100** - execute scheduled long running tasks, which depends on currently ended scheduled task. | ||
+ | * **Provisioning**: | ||
+ | * **-5000** - check disabled system | ||
+ | * **-1000** - compute attributes for provisioning (read attribute values from target system) | ||
+ | * **-500** - check readonly system | ||
+ | * **0** - execute provisioning (create / update / delete) | ||
+ | * **1000** - execute '' | ||
+ | * **5000** - archive processed provisioning operation. | ||
+ | |||
+ | Other orders can be found directly in application, | ||
+ | |||
+ | ===== Processor configuration ===== | ||
+ | |||
+ | Processors can be configured through ``Configurable`` interface by standard [[..: | ||
+ | |||
+ | ===== Implemented processors ===== | ||
+ | |||
+ | Basic save and delete processors are not listed. | ||
+ | ==== Automatic roles processors ==== | ||
+ | <code properties> | ||
+ | ## | ||
+ | ## approve create automatic role | ||
+ | idm.sec.core.processor.role-tree-node-create-approve-processor.enabled=true | ||
+ | # wf definition | ||
+ | idm.sec.core.processor.role-tree-node-create-approve-processor.wf=approve-create-automatic-role | ||
+ | ## | ||
+ | ## approve delete automatic role | ||
+ | idm.sec.core.processor.role-tree-node-delete-approve-processor.enabled=true | ||
+ | # wf definition | ||
+ | idm.sec.core.processor.role-tree-node-delete-approve-processor.wf=approve-delete-automatic-role | ||
+ | </ | ||
+ | |||
+ | ==== Notification on change monitored Identity fields ==== | ||
+ | * Check if defined fields on identity was changed. If yes, then send notification. | ||
+ | * As default is used this system template **identityMonitoredFieldsChanged**. | ||
+ | * Extended attributes is not supported now. | ||
+ | * Order of processor is **Integer.Max - 100**. We want to send notification on end of chain (after identity is presisted or provisioning are completed). | ||
+ | <code properties> | ||
+ | # Identity changed monitored fields - Check if defined fields on identity was changed. If yes, then send notification. | ||
+ | # Default is disabled | ||
+ | idm.sec.core.processor.identity-monitored-fields-processor.enabled=false | ||
+ | # Monitored fields on change (for Identity, extended attributes are not supported) | ||
+ | idm.sec.core.processor.identity-monitored-fields-processor.monitoredFields=firstName, | ||
+ | # Notification will be send to all identities with this role | ||
+ | idm.sec.core.processor.identity-monitored-fields-processor.recipientsRole=superAdminRole | ||
+ | </ | ||
+ | |||
+ | ==== Change user permissions workflow ==== | ||
+ | * Name of processor " | ||
+ | * This process ensures the approval of the request for change premissions. | ||
+ | <code properties> | ||
+ | # Default is enabled | ||
+ | idm.sec.core.processor.role-request-approval-processor.enabled=true | ||
+ | # Workflow process for change permissions (as default is " | ||
+ | idm.sec.core.processor.role-request-approval-processor.wf=approve-identity-change-permissions | ||
+ | </ | ||
+ | |||
+ | ==== Change user permissions workflow - Approval by the helpdesk department ==== | ||
+ | * The approving task will be assigned to all users with role Helpdesk. | ||
+ | <code properties> | ||
+ | # The role can be changed in the application configuration " | ||
+ | idm.sec.core.wf.approval.helpdesk.role=Helpdesk | ||
+ | # Default is disabled | ||
+ | idm.sec.core.wf.approval.helpdesk.enabled=false | ||
+ | </ | ||
+ | |||
+ | ==== Change user permissions workflow - Approval by the manager ==== | ||
+ | * The approving task will be assigned to all users evaluated as the managers of the applicant. The manager is defined based on the industrial relations of the applicant. | ||
+ | <code properties> | ||
+ | # Default is disabled | ||
+ | idm.sec.core.wf.approval.manager.enabled=false | ||
+ | </ | ||
+ | |||
+ | ==== Change user permissions workflow - Approval by the user administration department ==== | ||
+ | * The approving task will be assigned to all users with role Usermanager. | ||
+ | <code properties> | ||
+ | # The role can be changed in the application configuration " | ||
+ | idm.sec.core.wf.approval.usermanager.role=Usermanager | ||
+ | # Default is disabled | ||
+ | idm.sec.core.wf.approval.usermanager.enabled=false | ||
+ | </ | ||
+ | |||
+ | ==== Hr processes processors ==== | ||
+ | <code properties> | ||
+ | ## | ||
+ | ## HR process - enable identity' | ||
+ | ## for contracts that are both valid (meaning validFrom and validTill and disabled state) and | ||
+ | ## not excluded. | ||
+ | idm.sec.core.processor.identity-contract-enable-processor.enabled=true | ||
+ | # wf definition | ||
+ | idm.sec.core.processor.identity-contract-enable-processor.wf=hrEnableContract | ||
+ | ## | ||
+ | ## HR process - end or delete of identity' | ||
+ | ## for contracts that are not valid (meaning validFrom and validTill or disabled by state) and deleted. | ||
+ | ## If the processed contract was the last valid contract of the identity, the identity is disabled. | ||
+ | ## Additionally all added roles, which were assigned to the ended contract, are removed by the process. | ||
+ | idm.sec.core.processor.identity-contract-end-processor.enabled=true | ||
+ | # wf definition | ||
+ | idm.sec.core.processor.identity-contract-end-processor.wf=hrEndContract | ||
+ | ## | ||
+ | ## HR process - identity' | ||
+ | ## contracts that are both valid (meaning validFrom and validTill) and excluded. | ||
+ | ## If the processed contract was the last valid contract of the identity, the identity is disabled. | ||
+ | idm.sec.core.processor.identity-contract-exclusion-processor.enabled=true | ||
+ | # wf definition | ||
+ | idm.sec.core.processor.identity-contract-exclusion-processor.wf=hrContractExclusion | ||
+ | </ | ||
+ | |||
+ | ==== Provisioning after create, update or delete manually added guarantee for contract ==== | ||
+ | * Provisioning after manually add, update or remove guarantee is controlled by these two processors: **ContractGuaranteeSaveProvisioningProcessor** and **ContractGuaranteeDeleteProvisioningProcessor**. Provisioning for update or create is done **after** success save entity, but provisioning for delete is done **before** delete entity. Both processors are enabled by default. | ||
+ | |||
+ | <code properties> | ||
+ | ## Provisioning identity after add or update IdmContractGuaranteeDto | ||
+ | idm.sec.acc.processor.contract-guarantee-save.enabled=true | ||
+ | ## | ||
+ | ## Provisioning identity before IdmContractGuaranteeDto will be removed | ||
+ | idm.sec.acc.processor.contract-guarantee-delete.enabled=true | ||
+ | </ | ||
+ | |||
+ | ==== LongRunningTaskEndProcessor ==== | ||
+ | |||
+ | When some long running task ends, then '' | ||
+ | |||
+ | ==== LongRunningTaskExecuteDependentProcessor ==== | ||
+ | |||
+ | When some long running task ends, then '' | ||
+ | |||
+ | ==== ReportGenerateProcessor ==== | ||
+ | |||
+ | Processes '' | ||
+ | |||
+ | <code properties> | ||
+ | ## Enable / disable | ||
+ | idm.sec.rpt.processor.report-generate-processor.enabled=true | ||
+ | </ | ||
+ | |||
+ | ==== ReportGenerateEndProcessor ==== | ||
+ | |||
+ | Processes '' | ||
+ | |||
+ | <code properties> | ||
+ | ## Enable / disable | ||
+ | idm.sec.rpt.processor.report-generate-end-processor.enabled=true | ||
+ | </ | ||
+ | |||
+ | ==== ReportGenerateEndSendNotificationProcessor ==== | ||
+ | |||
+ | Processes '' | ||
+ | |||
+ | <code properties> | ||
+ | ## Enable / disable | ||
+ | idm.sec.rpt.processor.report-generate-end-send-notification-processor.enabled=true | ||
+ | </ | ||
+ | |||
+ | ==== IdentitySetPasswordProcessor ==== | ||
+ | |||
+ | Processes '' | ||
+ | |||
+ | Identity is starting, when their state is changed from '' | ||
+ | |||
+ | <code properties> | ||
+ | ## Enable / disable | ||
+ | idm.sec.acc.processor.identity-set-password-processor.enabled=true | ||
+ | </ | ||
+ | |||
+ | ==== EntityEventStartProcessor ==== | ||
+ | * Event content: '' | ||
+ | * Event type: '' | ||
+ | * Default order: **-1000** | ||
+ | |||
+ | Start execution of entity event. | ||
+ | |||
+ | <code properties> | ||
+ | ## Enable / disable | ||
+ | idm.sec.core.processor.entity-event-start-processor.enabled=true | ||
+ | </ | ||
+ | |||
+ | ==== EntityEventExecuteProcessor ==== | ||
+ | * Event content: '' | ||
+ | * Event type: '' | ||
+ | * Default order: **0** | ||
+ | |||
+ | <code properties> | ||
+ | ## Enable / disable | ||
+ | idm.sec.core.processor.entity-event-execute-processor.enabled=true | ||
+ | </ | ||
+ | |||
+ | Execute entity event - resurrects entity event and process her - execute all registered processors. | ||
+ | |||
+ | ==== EntityEventEndProcessor ==== | ||
+ | * Event content: '' | ||
+ | * Event type: '' | ||
+ | * Default order: **1000** | ||
+ | |||
+ | End execution of entity event - persist state only. | ||
+ | |||
+ | <code properties> | ||
+ | ## Enable / disable | ||
+ | idm.sec.core.processor.entity-event-end-processor.enabled=true | ||
+ | </ | ||
+ | |||
+ | ==== EntityEventDeleteExecutedProcessor ==== | ||
+ | * Event content: '' | ||
+ | * Event type: '' | ||
+ | * Default order: **5000** | ||
+ | |||
+ | Delete successfully executed entity events. | ||
+ | |||
+ | <code properties> | ||
+ | ## Enable / disable | ||
+ | idm.sec.core.processor.entity-event-delete-executed-processor.enabled=true | ||
+ | </ | ||
+ | |||
+ | |||
+ | ==== RoleCompositionAfterCreateProcessor ==== | ||
+ | |||
+ | @since 9.0.0 | ||
+ | |||
+ | * Event content: '' | ||
+ | * Event type: '' | ||
+ | * Default order: **0** | ||
+ | |||
+ | Assign sub roles for currently assigned roles, after composition (business role) is created. Update role composition is not supported now - '' | ||
+ | |||
+ | <code properties> | ||
+ | ## Enable / disable | ||
+ | idm.sec.core.processor.core-role-composition-after-create-processor.enabled=true | ||
+ | </ | ||
+ | |||
+ | ==== IdentityRoleAssignSubRolesProcessor ==== | ||
+ | |||
+ | @since 9.0.0 | ||
+ | |||
+ | * Event content: '' | ||
+ | * Event type: '' | ||
+ | * Default order: **500** | ||
+ | |||
+ | Assign sub roles of currently assigned identity roles: | ||
+ | * assign direct sub roles only, works recursively | ||
+ | * prevents cycles (just for sure) - adds processed roles into event property | ||
+ | |||
+ | <code properties> | ||
+ | ## Enable / disable | ||
+ | idm.sec.core.processor.core-identity-role-assign-subroles-processor.enabled=true | ||
+ | </ | ||
+ | |||
+ | ==== IdentityRoleDeleteAuthoritiesProcessor ==== | ||
+ | |||
+ | * Event content: '' | ||
+ | * Event type: '' | ||
+ | * Default order: **Integer.MAX_VALUE** | ||
+ | |||
+ | Checks modifications in identity authorities after role removal and disable authentication tokens. | ||
+ | |||
+ | <code properties> | ||
+ | ## Enable / disable | ||
+ | idm.sec.core.processor.identity-role-delete-authorities-processor.enabled=true | ||
+ | </ | ||
+ | |||
+ | ==== ContractPositionAutomaticRoleProcessor ==== | ||
+ | |||
+ | @since 9.1.0 | ||
+ | |||
+ | * Event content: '' | ||
+ | * Event type: '' | ||
+ | * Default order: **500** | ||
+ | |||
+ | Automatic roles recount while contract position is created or updated. | ||
+ | |||
+ | <code properties> | ||
+ | ## Enable / disable | ||
+ | idm.sec.core.processor.core-contract-position-automatic-role-processor.enabled=true | ||
+ | </ | ||
+ | |||
+ | ==== FormableSaveProcessor ==== | ||
+ | |||
+ | @since 9.2.0 | ||
+ | |||
+ | * Event content: '' | ||
+ | * Event type: '' | ||
+ | * Default order: **50** | ||
+ | |||
+ | Persists formable entity' | ||
+ | |||
+ | <code properties> | ||
+ | ## Enable / disable | ||
+ | idm.sec.core.processor.core-formable-save-processor.enabled=true | ||
+ | </ | ||
+ | |||
+ | |||
+ | ==== FormInstanceSaveProcessor ==== | ||
+ | |||
+ | @since 9.2.0 | ||
+ | |||
+ | * Event content: '' | ||
+ | * Event type: '' | ||
+ | * Default order: **0** | ||
+ | |||
+ | Persists form instance (eav attributes). | ||
+ | |||
+ | <code properties> | ||
+ | ## Enable / disable | ||
+ | idm.sec.core.processor.core-form-instance-save-processor.enabled=true | ||
+ | </ | ||
+ | |||
+ | ==== RoleCodeEnvironmentProcessor ==== | ||
+ | |||
+ | @since 9.3.0 | ||
+ | |||
+ | * Event content: '' | ||
+ | * Event type: '' | ||
+ | * Default order: **-100** | ||
+ | |||
+ | Appends environment into role code. Checks filled code, base code and environment. | ||
+ | |||
+ | <code properties> | ||
+ | ## Enable / disable | ||
+ | idm.sec.core.processor.core-role-code-environment-processor.enabled=true | ||
+ | </ | ||
+ | |||
+ | ==== Duplicate role processors ==== | ||
+ | |||
+ | {{page> | ||
+ | |||
+ | |||
+ | |||
+ | ===== Example ===== | ||
+ | ==== Synchronous processor ==== | ||
+ | |||
+ | If we want to get '' | ||
+ | <code java> | ||
+ | @Enabled(ExampleModuleDescriptor.MODULE_ID) | ||
+ | @Component(" | ||
+ | @Description(" | ||
+ | public class LogIdentityUpdateSyncProcessor | ||
+ | extends CoreEventProcessor< | ||
+ | implements IdentityProcessor { | ||
+ | |||
+ | /** | ||
+ | * Processor' | ||
+ | */ | ||
+ | public static final String PROCESSOR_NAME = " | ||
+ | private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory | ||
+ | .getLogger(LogIdentityUpdateSyncProcessor.class); | ||
+ | |||
+ | public LogIdentityUpdateSyncProcessor() { | ||
+ | // processing identity UPDATE event only | ||
+ | super(IdentityEventType.UPDATE); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public String getName() { | ||
+ | // processor' | ||
+ | return PROCESSOR_NAME; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public EventResult< | ||
+ | // event content - identity | ||
+ | IdmIdentityDto updateddIdentity = event.getContent(); | ||
+ | // log | ||
+ | LOG.info(" | ||
+ | // result | ||
+ | return new DefaultEventResult<> | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public int getOrder() { | ||
+ | // right after identity update | ||
+ | return CoreEvent.DEFAULT_ORDER + 1; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | |||
+ | ==== Asynchronous processor ==== | ||
+ | |||
+ | If we want to implement the same feature as above but asynchronously, | ||
+ | |||
+ | <code java> | ||
+ | @Enabled(ExampleModuleDescriptor.MODULE_ID) | ||
+ | @Component(" | ||
+ | @Description(" | ||
+ | public class LogIdentityUpdateAsyncProcessor | ||
+ | extends CoreEventProcessor< | ||
+ | implements IdentityProcessor { | ||
+ | |||
+ | /** | ||
+ | * Processor' | ||
+ | */ | ||
+ | public static final String PROCESSOR_NAME = " | ||
+ | private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory | ||
+ | .getLogger(LogIdentityUpdateAsyncProcessor.class); | ||
+ | |||
+ | public LogIdentityUpdateAsyncProcessor() { | ||
+ | // processing identity NOTIFY event only | ||
+ | super(IdentityEventType.NOTIFY); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public boolean conditional(EntityEvent< | ||
+ | // we want to process original UPDATE event only | ||
+ | // async NOTIFY event is published for CREATE, UPDATE, EAV_SAVE event types | ||
+ | return super.conditional(event) | ||
+ | && | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public String getName() { | ||
+ | // processor' | ||
+ | return PROCESSOR_NAME; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public EventResult< | ||
+ | // event content - identity | ||
+ | IdmIdentityDto updateddIdentity = event.getContent(); | ||
+ | // log | ||
+ | LOG.info(" | ||
+ | // result | ||
+ | return new DefaultEventResult<> | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public int getOrder() { | ||
+ | // notify event has their own process line - we can use default order | ||
+ | return CoreEvent.DEFAULT_ORDER; | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | |||
+ | ===== Future development ===== | ||
+ | |||
+ | * Skip duplicate event in "the bigger window" | ||
+ | * Support to persist confidential event properties. | ||
+ | * Support retry failed events | ||
+ | * Create FE component with entity state | ||
+ | * Notification about failed events (or report) | ||
+ | * Automatic role event doesn' | ||