Skip to content

Commit

Permalink
feat(engine): support composite incident handlers
Browse files Browse the repository at this point in the history
* adds new engine flag for enabling composite incident handlers so multiple
  incident handlers can be triggered for the same type

related to CAM-13569
closes camunda#1561
  • Loading branch information
bespaltovyj authored Oct 18, 2021
1 parent 2f8ce04 commit c11c7d2
Show file tree
Hide file tree
Showing 4 changed files with 586 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@
import org.camunda.bpm.engine.impl.identity.ReadOnlyIdentityProvider;
import org.camunda.bpm.engine.impl.identity.WritableIdentityProvider;
import org.camunda.bpm.engine.impl.identity.db.DbIdentityServiceProvider;
import org.camunda.bpm.engine.impl.incident.CompositeIncidentHandler;
import org.camunda.bpm.engine.impl.incident.DefaultIncidentHandler;
import org.camunda.bpm.engine.impl.incident.IncidentHandler;
import org.camunda.bpm.engine.impl.interceptor.CommandContextFactory;
Expand Down Expand Up @@ -761,6 +762,22 @@ public abstract class ProcessEngineConfigurationImpl extends ProcessEngineConfig

protected boolean isExecutionTreePrefetchEnabled = true;

/**
* If true, the incident handlers init as {@link CompositeIncidentHandler} and
* multiple incident handlers can be added for the same Incident type.
* However, only the result from the "main" incident handler will be returned.
* <p>
* All {@link customIncidentHandlers} will be added as sub handlers to {@link CompositeIncidentHandler} for same handler type.
* <p>
* By default, main handler is {@link DefaultIncidentHandler}.
* To override the main handler you need create {@link CompositeIncidentHandler} with your main IncidentHandler and
* init {@link incidentHandlers} before setting up the engine.
*
* @see CompositeIncidentHandler
* @see #initIncidentHandlers
*/
protected boolean isCompositeIncidentHandlersEnabled = false;

/**
* If true the process engine will attempt to acquire an exclusive lock before
* creating a deployment.
Expand Down Expand Up @@ -1325,14 +1342,21 @@ protected void initIncidentHandlers() {
incidentHandlers = new HashMap<>();

DefaultIncidentHandler failedJobIncidentHandler = new DefaultIncidentHandler(Incident.FAILED_JOB_HANDLER_TYPE);
incidentHandlers.put(failedJobIncidentHandler.getIncidentHandlerType(), failedJobIncidentHandler);
DefaultIncidentHandler failedExternalTaskIncidentHandler = new DefaultIncidentHandler(
Incident.EXTERNAL_TASK_HANDLER_TYPE);

if (isCompositeIncidentHandlersEnabled) {
addIncidentHandler(new CompositeIncidentHandler(failedJobIncidentHandler));
addIncidentHandler(new CompositeIncidentHandler(failedExternalTaskIncidentHandler));
} else {
addIncidentHandler(failedJobIncidentHandler);
addIncidentHandler(failedExternalTaskIncidentHandler);
}

DefaultIncidentHandler failedExternalTaskIncidentHandler = new DefaultIncidentHandler(Incident.EXTERNAL_TASK_HANDLER_TYPE);
incidentHandlers.put(failedExternalTaskIncidentHandler.getIncidentHandlerType(), failedExternalTaskIncidentHandler);
}
if (customIncidentHandlers != null) {
for (IncidentHandler incidentHandler : customIncidentHandlers) {
incidentHandlers.put(incidentHandler.getIncidentHandlerType(), incidentHandler);
addIncidentHandler(incidentHandler);
}
}
}
Expand Down Expand Up @@ -3791,6 +3815,16 @@ public IncidentHandler getIncidentHandler(String incidentType) {
return incidentHandlers.get(incidentType);
}

public void addIncidentHandler(IncidentHandler incidentHandler) {
IncidentHandler existsHandler = incidentHandlers.get(incidentHandler.getIncidentHandlerType());

if (existsHandler instanceof CompositeIncidentHandler) {
((CompositeIncidentHandler) existsHandler).add(incidentHandler);
} else {
incidentHandlers.put(incidentHandler.getIncidentHandlerType(), incidentHandler);
}
}

public Map<String, IncidentHandler> getIncidentHandlers() {
return incidentHandlers;
}
Expand Down Expand Up @@ -4114,6 +4148,15 @@ public ProcessEngineConfigurationImpl setStandaloneTasksEnabled(boolean standalo
return this;
}

public boolean isCompositeIncidentHandlersEnabled() {
return isCompositeIncidentHandlersEnabled;
}

public ProcessEngineConfigurationImpl setCompositeIncidentHandlersEnabled(boolean compositeIncidentHandlersEnabled) {
this.isCompositeIncidentHandlersEnabled = compositeIncidentHandlersEnabled;
return this;
}

public ScriptFactory getScriptFactory() {
return scriptFactory;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. Camunda licenses this file to you under the Apache License,
* Version 2.0; you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://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 org.camunda.bpm.engine.impl.incident;

import org.camunda.bpm.engine.ProcessEngineException;
import org.camunda.bpm.engine.impl.util.EnsureUtil;
import org.camunda.bpm.engine.runtime.Incident;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* <p>
* A composite incident handler that handles incidents of a certain type by the multiple handlers.
* The result of handling depends on main handler.
*
* @see #mainIncidentHandler
* </p>
* @see IncidentHandler
*/
public class CompositeIncidentHandler implements IncidentHandler {

protected IncidentHandler mainIncidentHandler;
protected final List<IncidentHandler> incidentHandlers = new ArrayList<>();

/**
* Constructor that takes a list of {@link IncidentHandler} that consume
* the incident.
*
* @param mainIncidentHandler the main incident handler {@link IncidentHandler} that consume the incident and return result.
* @param incidentHandlers the list of {@link IncidentHandler} that consume the incident.
*/
public CompositeIncidentHandler(IncidentHandler mainIncidentHandler, final List<IncidentHandler> incidentHandlers) {
initializeIncidentsHandlers(mainIncidentHandler, incidentHandlers);
}

/**
* Constructor that takes a varargs parameter {@link IncidentHandler} that
* consume the incident.
*
* @param mainIncidentHandler the main incident handler {@link IncidentHandler} that consume the incident and return result.
* @param incidentHandlers the list of {@link IncidentHandler} that consume the incident.
*/
public CompositeIncidentHandler(IncidentHandler mainIncidentHandler, final IncidentHandler... incidentHandlers) {
EnsureUtil.ensureNotNull("Incident handlers", (Object[]) incidentHandlers);
initializeIncidentsHandlers(mainIncidentHandler, Arrays.asList(incidentHandlers));
}

/**
* Initialize {@link #incidentHandlers} with data transfered from constructor
*
* @param incidentHandlers
*/
protected void initializeIncidentsHandlers(IncidentHandler mainIncidentHandler,
final List<IncidentHandler> incidentHandlers) {
EnsureUtil.ensureNotNull("Incident handler", mainIncidentHandler);
this.mainIncidentHandler = mainIncidentHandler;

EnsureUtil.ensureNotNull("Incident handlers", incidentHandlers);
for (IncidentHandler incidentHandler : incidentHandlers) {
add(incidentHandler);
}
}

/**
* Adds the {@link IncidentHandler} to the list of
* {@link IncidentHandler} that consume the incident.
*
* @param incidentHandler the {@link IncidentHandler} that consume the incident.
*/
public void add(final IncidentHandler incidentHandler) {
EnsureUtil.ensureNotNull("Incident handler", incidentHandler);
String incidentHandlerType = getIncidentHandlerType();
if (!incidentHandlerType.equals(incidentHandler.getIncidentHandlerType())) {
throw new ProcessEngineException(
"Incorrect incident type handler in composite handler with type: " + incidentHandlerType);
}
this.incidentHandlers.add(incidentHandler);
}

@Override
public String getIncidentHandlerType() {
return mainIncidentHandler.getIncidentHandlerType();
}

@Override
public Incident handleIncident(IncidentContext context, String message) {
Incident incident = mainIncidentHandler.handleIncident(context, message);
for (IncidentHandler incidentHandler : this.incidentHandlers) {
incidentHandler.handleIncident(context, message);
}
return incident;
}

@Override
public void resolveIncident(IncidentContext context) {
mainIncidentHandler.resolveIncident(context);
for (IncidentHandler incidentHandler : this.incidentHandlers) {
incidentHandler.resolveIncident(context);
}
}

@Override
public void deleteIncident(IncidentContext context) {
mainIncidentHandler.deleteIncident(context);
for (IncidentHandler incidentHandler : this.incidentHandlers) {
incidentHandler.deleteIncident(context);
}
}
}
Loading

0 comments on commit c11c7d2

Please sign in to comment.