Skip to content

Commit

Permalink
Close #312: Eventing Bridge
Browse files Browse the repository at this point in the history
  • Loading branch information
silvanbrenner authored and tobiasschaefer committed Aug 24, 2021
1 parent a86c2be commit 59693ef
Show file tree
Hide file tree
Showing 11 changed files with 1,115 additions and 0 deletions.
65 changes: 65 additions & 0 deletions README.md
Expand Up @@ -48,6 +48,7 @@ Micronaut + Camunda = :heart:
* [Custom Process Engine Configuration](#custom-process-engine-configuration)
* [Custom Job Executor Configuration](#custom-job-executor-configuration)
* [Transaction Management](#transaction-management)
* [Eventing Bridge](#eventing-bridge)
* [Process Tests](#process-tests)
* [Docker](#docker)
* [Updating Camunda](#updating-camunda)
Expand All @@ -64,6 +65,7 @@ Micronaut + Camunda = :heart:
* The process engine and related services, e.g. RuntimeService, RepositoryService, ..., are provided as lazy initialized beans and [can be injected](#camunda-integration).
* Micronaut beans are resolved from the application context if they are [referenced by expressions or Java class names](#java-delegates) within the process models.
* The process engine [integrates with Micronaut's transaction manager](#transaction-management). Optionally, micronaut-data-jdbc or micronaut-data-jpa are supported.
* Eventing Bridge that maps Camunda Events to Micronaut ApplicationEvents.
* The process engine can be configured with [generic properties](#generic-properties).
* The [Camunda REST API and the Webapps](#camunda-rest-api-and-webapps) are supported (currently only for Jetty).
* The [Camunda Enterprise Edition (EE)](#camunda-enterprise-edition-ee) is supported.
Expand Down Expand Up @@ -636,6 +638,69 @@ And also add the annotation processor to every (!) `annotationProcessorPaths` el

and then configure JPA as described in [micronaut-sql documentation](https://micronaut-projects.github.io/micronaut-sql/latest/guide/#hibernate).


## Eventing Bridge

The Eventing Bridge maps Camunda Events to Micronaut [ApplicationEvents](https://docs.micronaut.io/latest/api/io/micronaut/context/event/ApplicationEvent.html). It's possible to configure three different
event streams:
* Task: All events depending on UserTasks (UserTasks are Created, Assigned, Completed)
* Execution: All execution events (Activities are Started, Ended and Transitions are being taken)
* History: All history events

### Configuration
```yaml
camunda:
eventing:
task: true
execution: true
history: true
```

### Event Listener Implementation
To consume Micronaut ApplicationEvents you can implement the interface ApplicationEventListener or use the
@EventListener annotation.

<details>
<summary>Click to show example with ApplicationEventListener interface</summary>

```java
public class SampleEventListener implements ApplicationEventListener<TaskEvent> {
private static final Logger log = LoggerFactory.getLogger(SampleEventListener.class);

@Override
public void onApplicationEvent(TaskEvent event) {
log.info("new TaskEvent: EventName={}, Assignee={}", event.getEventName(), event.getAssignee());
}
}
```
</details>

<details>
<summary>Click to show example with @EventListener</summary>

```java
@Singleton
public class SampleEventListener {
private static final Logger log = LoggerFactory.getLogger(SampleEventListener.class);

@EventListener
public void onExecutionEvent(ExecutionEvent event) {
log.info("new ExecutionEvent: {}", event.getEventName());
}

@EventListener
public void onTaskEvent(TaskEvent event) {
log.info("new TaskEvent: {}", event.getEventName());
}

@EventListener
public void onTaskEvent(HistoryEvent event) {
log.info("new HistoryEvent: {}", event.getEventType());
}
}
```
</details>

## Process Tests

Process tests can easily be implemented with JUnit 5 by adding the `camunda-bpm-assert` library as a dependency:
Expand Down
@@ -0,0 +1,49 @@
/*
* Copyright 2021 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package info.novatec.micronaut.camunda.bpm.example;

import info.novatec.micronaut.camunda.bpm.feature.eventing.ExecutionEvent;
import info.novatec.micronaut.camunda.bpm.feature.eventing.TaskEvent;
import io.micronaut.runtime.event.annotation.EventListener;
import org.camunda.bpm.engine.impl.history.event.HistoryEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Singleton;

@Singleton
public class SampleEventListener {

private static final Logger log = LoggerFactory.getLogger(SampleEventListener.class);

@EventListener
public void onExecutionEvent(ExecutionEvent event) {
log.info("new ExecutionEvent: EventName={}, CurrentActivityName={}", event.getEventName(),
event.getCurrentActivityName());
}

@EventListener
public void onTaskEvent(TaskEvent event) {
log.info("new TaskEvent: EventName={}, Assignee={}", event.getEventName(), event.getAssignee());
}

@EventListener
public void onTaskEvent(HistoryEvent event) {
log.info("new HistoryEvent: EventType={}", event.getEventType());
}

}
Expand Up @@ -16,3 +16,7 @@ camunda:
enabled: true
filter:
create: "All tasks"
eventing:
task: false
execution: false
history: false
Expand Up @@ -61,6 +61,9 @@ public interface Configuration {
@NotNull
GenericProperties getGenericProperties();

@NotNull
Eventing getEventing();

/**
* Provide a URL to a license file; if no URL is present it will check your classpath for a file called "camunda-license.txt".
*
Expand Down Expand Up @@ -401,4 +404,31 @@ interface Rest {
boolean isBasicAuthEnabled();
}

@ConfigurationProperties("eventing")
interface Eventing {

/**
* Publish Events of execution listener.
*
* @return is enabled?
*/
@Bindable(defaultValue = "false")
boolean isExecution();

/**
* Publish Events of task listener.
*
* @return is enabled?
*/
@Bindable(defaultValue = "false")
boolean isTask();

/**
* Publish Event of history handler.
*
* @return is enabled?
*/
@Bindable(defaultValue = "false")
boolean isHistory();
}
}
@@ -0,0 +1,94 @@
/*
* Copyright 2021 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package info.novatec.micronaut.camunda.bpm.feature.eventing;

import info.novatec.micronaut.camunda.bpm.feature.Configuration;
import io.micronaut.context.annotation.Requires;
import io.micronaut.context.event.ApplicationEventPublisher;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.impl.bpmn.parser.BpmnParseListener;
import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.camunda.bpm.engine.impl.cfg.ProcessEnginePlugin;
import org.camunda.bpm.engine.impl.history.handler.HistoryEventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Singleton;
import java.util.ArrayList;

/**
* Plugin to map Camunda Events to Micronaut {@link io.micronaut.context.event.ApplicationEvent}'s.
*
* @author Silvan Brenner
*/
// Implementation based on https://github.com/camunda/camunda-bpm-platform/blob/master/spring-boot-starter/starter/src/main/java/org/camunda/bpm/spring/boot/starter/event/EventPublisherPlugin.java
@Singleton
@Requires(condition = EventingPublisherPluginCondition.class)
public class EventingPublisherPlugin implements ProcessEnginePlugin {

private static final Logger log = LoggerFactory.getLogger(EventingPublisherPlugin.class);

protected final Configuration configuration;
protected final ApplicationEventPublisher publisher;
protected final BpmnParseListener publishDelegateParseListener;
protected final HistoryEventHandler publishHistoryEventHandler;

public EventingPublisherPlugin(Configuration configuration, ApplicationEventPublisher publisher, BpmnParseListener publishDelegateParseListener, HistoryEventHandler publishHistoryEventHandler) {
this.configuration = configuration;
this.publisher = publisher;
this.publishDelegateParseListener = publishDelegateParseListener;
this.publishHistoryEventHandler = publishHistoryEventHandler;
}

@Override
public void preInit(ProcessEngineConfigurationImpl processEngineConfiguration) {
if (configuration.getEventing().isTask() || configuration.getEventing().isExecution()) {
log.info("Initialized Micronaut Event Engine Plugin.");
if (configuration.getEventing().isTask()) {
log.info("Task events will be published as Micronaut Events.");
} else {
log.info("Task eventing is disabled via property.");
}

if (configuration.getEventing().isExecution()) {
log.info("Execution events will be published as Micronaut Events.");
} else {
log.info("Execution eventing is disabled via property.");
}
if (processEngineConfiguration.getCustomPostBPMNParseListeners() == null) {
processEngineConfiguration.setCustomPostBPMNParseListeners(new ArrayList<>());
}
processEngineConfiguration.getCustomPostBPMNParseListeners()
.add(publishDelegateParseListener);
}
if (configuration.getEventing().isHistory()) {
log.info("History events will be published as Micronaut events.");
processEngineConfiguration.getCustomHistoryEventHandlers()
.add(publishHistoryEventHandler);
} else {
log.info("History eventing is disabled via property.");
}
}

@Override
public void postInit(ProcessEngineConfigurationImpl processEngineConfiguration) {
}

@Override
public void postProcessEngineBuild(ProcessEngine processEngine) {
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2021 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package info.novatec.micronaut.camunda.bpm.feature.eventing;

import info.novatec.micronaut.camunda.bpm.feature.Configuration;
import io.micronaut.context.condition.Condition;
import io.micronaut.context.condition.ConditionContext;

/**
* Condition to find out if the {@link EventingPublisherPlugin} should be enabled or not.
*
* @author Silvan Brenner
*/
public class EventingPublisherPluginCondition implements Condition {

@Override
public boolean matches(ConditionContext context) {
Configuration.Eventing eventing = context.getBean(Configuration.class).getEventing();
return eventing.isExecution() || eventing.isTask() || eventing.isHistory();
}
}

0 comments on commit 59693ef

Please sign in to comment.