Skip to content

Commit

Permalink
impl, added docu
Browse files Browse the repository at this point in the history
Issue #828
  • Loading branch information
rsoika committed May 4, 2023
1 parent 8ed9b69 commit 862c634
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,11 @@
import java.util.logging.Level;
import java.util.logging.Logger;

import jakarta.annotation.security.DeclareRoles;
import jakarta.annotation.security.RolesAllowed;

import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.jpa.EventLog;

import jakarta.annotation.security.DeclareRoles;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ejb.Stateless;
import jakarta.ejb.TransactionAttribute;
import jakarta.ejb.TransactionAttributeType;
Expand Down Expand Up @@ -81,11 +80,11 @@
*/

@DeclareRoles({ "org.imixs.ACCESSLEVEL.NOACCESS", "org.imixs.ACCESSLEVEL.READERACCESS",
"org.imixs.ACCESSLEVEL.AUTHORACCESS", "org.imixs.ACCESSLEVEL.EDITORACCESS",
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
"org.imixs.ACCESSLEVEL.AUTHORACCESS", "org.imixs.ACCESSLEVEL.EDITORACCESS",
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
@RolesAllowed({ "org.imixs.ACCESSLEVEL.NOACCESS", "org.imixs.ACCESSLEVEL.READERACCESS",
"org.imixs.ACCESSLEVEL.AUTHORACCESS", "org.imixs.ACCESSLEVEL.EDITORACCESS",
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
"org.imixs.ACCESSLEVEL.AUTHORACCESS", "org.imixs.ACCESSLEVEL.EDITORACCESS",
"org.imixs.ACCESSLEVEL.MANAGERACCESS" })
@Stateless
public class EventLogService {

Expand Down Expand Up @@ -208,7 +207,7 @@ public List<EventLog> findEventsByTopic(int maxCount, String... topic) {
/**
* Finds events for one or many given topics within the current timeout.
* <p>
* The attribte 'timeout' is optional. If the timeout is set to a future point
* The attribute 'timeout' is optional. If the timeout is set to a future point
* of time, the event will be ignored by this method.
*
* @param maxCount - maximum count of events to be returned
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Imixs-Workflow
*
* Copyright (C) 2001-2020 Imixs Software Solutions GmbH,
* http://www.imixs.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You can receive a copy of the GNU General Public
* License at http://www.gnu.org/licenses/gpl.html
*
* Project:
* https://www.imixs.org
* https://github.com/imixs/imixs-workflow
*
* Contributors:
* Imixs Software Solutions GmbH - Project Management
* Ralph Soika - Software Developer
*/

package org.imixs.workflow.engine.plugins;

import java.util.Calendar;
import java.util.logging.Logger;

import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.engine.EventLogService;
import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.util.XMLParser;

import jakarta.inject.Inject;

/**
* The Imixs EventLog plugin can be used to create a EventLog entry during
* processing an event. The plugin can be configured by the activity
* result :
* <p>
* Example:
* <p>
*
* <pre>
{@code
<eventlog name="snapshot.export">
<ref>$uniqueid</ref>
<timeout>60000</timeout>
<document>
<amount>500.00</amount>
<department>Finance</department>
</document>
</eventlog>
}
* </pre>
* <p>
*
* An EventLog entry can be processed by internal or external services.
* See: https://www.imixs.org/doc/engine/eventlogservice.html
*
* @author rsoika
*
*/
public class EventLogPlugin extends AbstractPlugin {
public static final String INVALID_FORMAT = "INVALID_FORMAT";

private static Logger logger = Logger.getLogger(EventLogPlugin.class.getName());

@Inject
EventLogService eventLogService;

@Override
public ItemCollection run(ItemCollection documentContext, ItemCollection event) throws PluginException {

// parse for eventlog definition....
ItemCollection eventLogConfig = this.getWorkflowService().evalWorkflowResult(event, "eventlog", documentContext,
true);
if (eventLogConfig == null || eventLogConfig.getItemNames().size() == 0) {
// no op - return
return documentContext;
}

// now iterate over all taxonomy definitions....
for (String name : eventLogConfig.getItemNames()) {
String xmlDef = eventLogConfig.getItemValueString(name);
ItemCollection eventLogData = XMLParser.parseItemStructure(xmlDef);

if (eventLogData != null) {
String ref = eventLogData.getItemValueString("ref");
String documentXML = eventLogData.getItemValueString("document");
long timeout = eventLogData.getItemValueLong("timeout");
Calendar cal = null;
// create event log entry...
if (timeout > 0) {
cal = Calendar.getInstance();
cal.setTimeInMillis(System.currentTimeMillis() + timeout);
}
// do we have a document definition?
if (!documentXML.isEmpty()) {
ItemCollection docData = XMLParser.parseItemStructure(documentXML);
// write eventLog entry...
eventLogService.createEvent(name, ref, docData.getAllItems(), cal);
} else {
// write eventLog entry...
eventLogService.createEvent(name, ref, cal);
}
}
}

return documentContext;
}

}
85 changes: 51 additions & 34 deletions src/site/markdown/engine/eventlogservice.md
Original file line number Diff line number Diff line change
@@ -1,64 +1,81 @@
# The EventLogService
# The EventLogService

The EventLogService is used to create and manage event log entries within a running transaction.
EventLog entries can be processed by a client in a secure, asynchronous and transactional manner.

Only in case the transaction from the source event was committed successfully, the event log entry can be read by a client. For example the LuceneUpdateService uses an event log entry to update the index only if a transaction was successful completed. This is also known as the 'Change Data Capture' design pattern.

## Change Data Capture (CDC)
An event that occurs during an update or a processing function within a transaction becomes a fact when the transaction completes successfully. The EventLogService can be used to create this kind of "Change Data Capture" events.
For example the LuceneUpdateService should update the index of a document only if the document was successfully written to the database. This can be ensured with the help of the EventLogService.

An event that occurs during an update or a processing function within a transaction becomes a fact when the transaction completes successfully. The EventLogService can be used to create this kind of "Change Data Capture" events.
For example the LuceneUpdateService should update the index of a document only if the document was successfully written to the database. This can be ensured with the help of the EventLogService.

The service is bound to the current PersistenceContext and stores a EventLog entities directly into the database. An EventLog entry can be queried by clients through this service.

@EJB
EventLogService eventLogService;
....
// BEGIN Transaction A
eventLogService.createEvent(workitem.getUniqueID(), "MY_TOPIC");
....
// END Transaction A
.......
// BEGIN Transaction B
List<org.imixs.workflow.engine.jpa.EventLog> eventList = eventLogService.findEvents("MY_TOPIC",100);
for (org.imixs.workflow.engine.jpa.EventLog eventLogEntry : eventList) {
// the event created in transaction A is no visible...
....
}
// END Transaction B
@EJB
EventLogService eventLogService;
....
// BEGIN Transaction A
eventLogService.createEvent(workitem.getUniqueID(), "MY_TOPIC");
....
// END Transaction A
.......


// BEGIN Transaction B
List<org.imixs.workflow.engine.jpa.EventLog> eventList = eventLogService.findEvents("MY_TOPIC",100);
for (org.imixs.workflow.engine.jpa.EventLog eventLogEntry : eventList) {
// the event created in transaction A is no visible...
....
}
// END Transaction B

Typically a new EventLog entity is created within the same transaction of the main processing or update life cycle. With this mechanism a client can be
sure that eventLogEntries returned by the EventLogService are created during a committed Transaction. If the transaction was rolled back for some reason, the EventLog entry will never be written to the database.



## The EventLog Entity

The EventLog entity describes a unique event created during the processing life-cycle of a workitem or the update life-cycle of a Document.

An EventLog is an immutable entity. The object contains the following properties:

* id - identifier for the event log entry
* ref - the reference id of the corresponding workitem or document entity
* topic - the topic of the eventlog
* created - the creation timestamp
* data - an optional data field
* timeout - an optional timestamp indicated the earliest processing time.
- id - identifier for the event log entry
- ref - the reference id of the corresponding workitem or document entity
- topic - the topic of the eventlog
- created - the creation timestamp
- data - an optional data field
- timeout - an optional timestamp indicated the earliest processing time.

The 'data' attribute of an eventLog is optional and can hold any kind of event specific data (e.g. a Mail Message).

**Note:** for the same document reference ($uniqueid) there can exist different eventlog entries. Eventlog entries are unique over there internal ID. You can use the method _findEventsByRef_ to verify if a event log entry for a defined Reference was already created by another transaction.
**Note:** for the same document reference ($uniqueid) there can exist different eventlog entries. Eventlog entries are unique over there internal ID. You can use the method _findEventsByRef_ to verify if a event log entry for a defined Reference was already created by another transaction.

## The EventLogPlugin

## TransactionID
The Imixs Plugin class ` org.imixs.workflow.engine.plugins.EventLogPlugin` can be used to create a EventLog entry during
processing an event. The plugin can be configured by the activity result :

In different to a document entity, a workitem entity hold a *$transactionID* identifying the last processing life-cycle. When an eventLog entry is consumed asynchronous, a client may verify the *$transactionID* item stored in the data field with the last *$transactionID* stored in the workitem. In case the *$transactionID* has changed a client can discard the eventLog entry. This mechanism ensures that an eventLog entity is tied to a specific unique transaction only.
Example:

```
<eventlog name="MY-TOPIC">
<ref><itemvalue>$uniqueid</itemvalue></ref>
<timeout>60000</timeout>
<document>
<amount>500.00</amount>
<department>Finance</department>
</document>
</eventlog>
```

This definition will create a new EventLog entry with the topic `MY-TOPIC` pointing to the current workitem. The EventLog entry also includes an optional data structure with the items 'amount' and 'department'.

## TransactionID

For example an AsyncEvent must only be executed if the *$transactionID* matches the current workitem status.
In different to a document entity, a workitem entity hold a _$transactionID_ identifying the last processing life-cycle. When an eventLog entry is consumed asynchronous, a client may verify the _$transactionID_ item stored in the data field with the last _$transactionID_ stored in the workitem. In case the _$transactionID_ has changed a client can discard the eventLog entry. This mechanism ensures that an eventLog entity is tied to a specific unique transaction only.

For example an AsyncEvent must only be executed if the _$transactionID_ matches the current workitem status.

## Timeout

The optional data attribute *timeout* .....
The optional data attribute _timeout_ of an EventLog entry can be used to delay its execution. The EventLogService method `findEventsByTimeout` can request only eventLogEntries with a timeout indicator which are in due.

0 comments on commit 862c634

Please sign in to comment.