Skip to content

Commit

Permalink
More descriptive error messages
Browse files Browse the repository at this point in the history
* Add / Extend toString to some entities
* Use full entities in message for FlowableException
* Log non HTTP 500 exceptions under debug in BaseExceptionHandlerAdvice
* Include request method and URI in log in BaseExceptionHandlerAdvice
  • Loading branch information
filiphr committed Nov 30, 2023
1 parent 58be512 commit cd50dac
Show file tree
Hide file tree
Showing 195 changed files with 808 additions and 423 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public String convertAppModelToJson(AppModel appModel) {
try {
return objectMapper.writeValueAsString(appModel);
} catch (Exception e) {
throw new FlowableException("Error writing app model to json", e);
throw new FlowableException("Error writing app model " + appModel.getKey() + " to json", e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public String startCaseInstanceByKey(String caseDefinitionKey, String predefined
@Override
public void handleSignalEvent(EventSubscriptionEntity eventSubscription, Map<String, Object> variables) {
if (StringUtils.isEmpty(eventSubscription.getSubScopeId())) {
throw new FlowableException("Plan item instance for event subscription can not be found with empty sub scope id value");
throw new FlowableException("Plan item instance for " + eventSubscription + " can not be found with empty sub scope id value");
}

CmmnRuntimeService cmmnRuntimeService = cmmnEngineConfiguration.getCmmnRuntimeService();
Expand All @@ -107,7 +107,7 @@ public void handleSignalEvent(EventSubscriptionEntity eventSubscription, Map<Str
.singleResult();

if (planItemInstance == null) {
throw new FlowableException("Plan item instance for event subscription can not be found with sub scope id " + eventSubscription.getSubScopeId());
throw new FlowableException("Plan item instance for " + eventSubscription + " can not be found with sub scope id " + eventSubscription.getSubScopeId());
}

cmmnRuntimeService.createPlanItemInstanceTransitionBuilder(planItemInstance.getId())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,8 @@ public void testDeleteCaseTaskShouldNotBePossible() {

assertThatThrownBy(() -> processEngineTaskService.deleteTask(caseTasks.get(0).getId()))
.isExactlyInstanceOf(FlowableException.class)
.hasMessageContaining("The task cannot be deleted")
.hasMessageContaining("The Task[")
.hasMessageContaining("cannot be deleted")
.hasMessageContaining("running case");

cmmnTaskService.complete(caseTasks.get(0).getId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,14 @@ public void testSimpleCombined() {

assertThatThrownBy(() -> processEngineManagementService.createExternalWorkerCompletionBuilder(cmmnAcquiredJob.getId(), "cmmnWorker").complete())
.isExactlyInstanceOf(FlowableException.class)
.hasMessage("External worker job with id " + cmmnAcquiredJob.getId()
+ " is not bpmn scoped. This command can only handle bpmn scoped external worker jobs");
.hasMessageContaining("ExternalWorkerJobEntity[id=" + cmmnAcquiredJob.getId())
.hasMessageContaining("is not bpmn scoped. This command can only handle bpmn scoped external worker jobs");

assertThatThrownBy(
() -> processEngineManagementService.createExternalWorkerCompletionBuilder(cmmnAcquiredJob.getId(), "cmmnWorker").bpmnError("errorCode"))
.isExactlyInstanceOf(FlowableException.class)
.hasMessage("External worker job with id " + cmmnAcquiredJob.getId()
+ " is not bpmn scoped. This command can only handle bpmn scoped external worker jobs");
.hasMessageContaining("ExternalWorkerJobEntity[id=" + cmmnAcquiredJob.getId())
.hasMessageContaining("is not bpmn scoped. This command can only handle bpmn scoped external worker jobs");

cmmnManagementService.createCmmnExternalWorkerTransitionBuilder(cmmnAcquiredJob.getId(), "cmmnWorker").complete();

Expand All @@ -91,13 +91,13 @@ public void testSimpleCombined() {

assertThatThrownBy(() -> cmmnManagementService.createCmmnExternalWorkerTransitionBuilder(bpmnAcquiredJob.getId(), "bpmnWorker").complete())
.isExactlyInstanceOf(FlowableException.class)
.hasMessage("External worker job with id " + bpmnAcquiredJob.getId()
+ " is not cmmn scoped. This command can only handle cmmn scoped external worker jobs");
.hasMessageContaining("ExternalWorkerJobEntity[id=" + bpmnAcquiredJob.getId())
.hasMessageContaining("is not cmmn scoped. This command can only handle cmmn scoped external worker jobs");

assertThatThrownBy(() -> cmmnManagementService.createCmmnExternalWorkerTransitionBuilder(bpmnAcquiredJob.getId(), "bpmnWorker").terminate())
.isExactlyInstanceOf(FlowableException.class)
.hasMessage("External worker job with id " + bpmnAcquiredJob.getId()
+ " is not cmmn scoped. This command can only handle cmmn scoped external worker jobs");
.hasMessageContaining("ExternalWorkerJobEntity[id=" + bpmnAcquiredJob.getId())
.hasMessageContaining("is not cmmn scoped. This command can only handle cmmn scoped external worker jobs");

processEngineManagementService.createExternalWorkerCompletionBuilder(bpmnAcquiredJob.getId(), "bpmnWorker").complete();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1372,7 +1372,8 @@ public void testDeleteProcessTaskShouldNotBePossible() {

assertThatThrownBy(() -> cmmnTaskService.deleteTask(task.getId()))
.isExactlyInstanceOf(FlowableException.class)
.hasMessageContaining("The task cannot be deleted")
.hasMessageContaining("The Task[")
.hasMessageContaining("cannot be deleted")
.hasMessageContaining("running process");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ protected void internalExecute() {
if (planItemDefinition instanceof Task) {
createAsyncJob((Task) planItemDefinition);
} else {
throw new FlowableException("Programmatic error: this operation can only be planned for Task plan item definitions");
throw new FlowableException("Programmatic error: this operation can only be planned for Task plan item definitions. " + planItemInstanceEntity);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ protected void executeActivityBehavior() {
activityBehavior.execute(planItemInstanceEntity);

} else {
throw new FlowableException("PlanItemInstance " + planItemInstanceEntity + " does not have a behavior");
throw new FlowableException(planItemInstanceEntity + " does not have a behavior");

}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ protected void executeTrigger() {
Object behaviorObject = planItemInstanceEntity.getPlanItem().getBehavior();
if (!(behaviorObject instanceof CmmnTriggerableActivityBehavior)) {
throw new FlowableException("Cannot trigger a plan item which activity behavior does not implement the "
+ CmmnTriggerableActivityBehavior.class + " interface");
+ CmmnTriggerableActivityBehavior.class + " interface in " + planItemInstanceEntity);
}
CmmnTriggerableActivityBehavior behavior = (CmmnTriggerableActivityBehavior) planItemInstanceEntity.getPlanItem().getBehavior();
if (behavior instanceof CoreCmmnTriggerableActivityBehavior) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ protected String getExpressionValue(String value, PlanItemInstanceEntity planIte
return expressionValue.toString();
}

throw new FlowableException("Unable to resolve expression value for " + value);
throw new FlowableException("Unable to resolve expression value for " + value + " in " + planItemInstanceEntity);
}

protected Collection<String> getExpressionListValue(String value, PlanItemInstanceEntity planItemInstanceEntity, ExpressionManager expressionManager) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public void execute(CommandContext commandContext, PlanItemInstanceEntity planIt

}
if (StringUtils.isEmpty(caseDefinitionKey)) {
throw new FlowableException("Could not start case instance: no case reference defined");
throw new FlowableException("Could not start case instance: no case reference defined in " + planItemInstanceEntity);
}

CaseInstanceBuilder caseInstanceBuilder = new CaseInstanceBuilderImpl().caseDefinitionKey(caseDefinitionKey);
Expand Down Expand Up @@ -233,7 +233,7 @@ public void deleteChildEntity(CommandContext commandContext, DelegatePlanItemIns
}

} else {
throw new FlowableException("Can only delete a child entity for a plan item with reference type " + ReferenceTypes.PLAN_ITEM_CHILD_CASE);
throw new FlowableException("Can only delete a child entity for a plan item with reference type " + ReferenceTypes.PLAN_ITEM_CHILD_CASE + " for " + delegatePlanItemInstance);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public DecisionTaskActivityBehavior(Expression decisionRefExpression, DecisionTa
public void execute(CommandContext commandContext, PlanItemInstanceEntity planItemInstanceEntity) {
DmnDecisionService dmnRuleService = CommandContextUtil.getDmnRuleService(commandContext);
if (dmnRuleService == null) {
throw new FlowableException("Could not execute decision instance: no dmn service found.");
throw new FlowableException("Could not execute decision instance: no dmn service found. For " + planItemInstanceEntity);
}

String externalRef = null;
Expand All @@ -76,7 +76,7 @@ public void execute(CommandContext commandContext, PlanItemInstanceEntity planIt
}

if (StringUtils.isEmpty(externalRef)) {
throw new FlowableException("Could not execute decision: no externalRef defined");
throw new FlowableException("Could not execute decision: no externalRef defined for " + planItemInstanceEntity);
}
}

Expand Down Expand Up @@ -111,25 +111,25 @@ public void execute(CommandContext commandContext, PlanItemInstanceEntity planIt
DecisionExecutionAuditContainer decisionExecutionAuditContainer = executeDecisionBuilder.executeWithAuditTrail();

if (decisionExecutionAuditContainer == null) {
throw new FlowableException("DMN decision with key " + externalRef + " was not executed.");
throw new FlowableException("DMN decision with key " + externalRef + " was not executed. For " + planItemInstanceEntity);
}

if (decisionExecutionAuditContainer.isFailed()) {
throw new FlowableException("DMN decision with key " + externalRef + " execution failed. Cause: " + decisionExecutionAuditContainer.getExceptionMessage());
throw new FlowableException("DMN decision with key " + externalRef + " execution failed. Cause: " + decisionExecutionAuditContainer.getExceptionMessage() + ". For " + planItemInstanceEntity);
}

/* Throw error if there were no rules hit when the flag indicates to do this. */
String throwErrorFieldValue = getFieldString(EXPRESSION_DECISION_TABLE_THROW_ERROR_FLAG);
if (decisionExecutionAuditContainer.getDecisionResult().isEmpty() && throwErrorFieldValue != null) {
if ("true".equalsIgnoreCase(throwErrorFieldValue)) {
throw new FlowableException("DMN decision with key " + externalRef + " did not hit any rules for the provided input.");
throw new FlowableException("DMN decision with key " + externalRef + " did not hit any rules for the provided input. For " + planItemInstanceEntity);

} else if (!"false".equalsIgnoreCase(throwErrorFieldValue)) {
Expression expression = CommandContextUtil.getExpressionManager(commandContext).createExpression(throwErrorFieldValue);
Object expressionValue = expression.getValue(planItemInstanceEntity);

if (expressionValue instanceof Boolean && ((Boolean) expressionValue)) {
throw new FlowableException("DMN decision with key " + externalRef + " did not hit any rules for the provided input.");
throw new FlowableException("DMN decision with key " + externalRef + " did not hit any rules for the provided input. For " + planItemInstanceEntity);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ protected String resolveEventDefinitionKey(PlanItemInstanceEntity planItemInstan
}

if (key == null) {
throw new FlowableException("Could not resolve key from expression: " + eventDefinitionKeyExpression);
throw new FlowableException("Could not resolve key from expression: " + eventDefinitionKeyExpression + " for " + planItemInstanceEntity);
}

return key.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public void execute(CommandContext commandContext, PlanItemInstanceEntity planIt

String jobTopicExpression = beforeContext.getJobTopicExpression();
if (StringUtils.isEmpty(jobTopicExpression)) {
throw new FlowableException("no topic expression configured");
throw new FlowableException("no topic expression configured for " + planItemInstanceEntity);
}

JobServiceConfiguration jobServiceConfiguration = cmmnEngineConfiguration.getJobServiceConfiguration();
Expand Down Expand Up @@ -102,7 +102,7 @@ public void execute(CommandContext commandContext, PlanItemInstanceEntity planIt
if (expressionValue != null && !expressionValue.toString().isEmpty()) {
job.setJobHandlerConfiguration(expressionValue.toString());
} else {
throw new FlowableException("Expression " + jobTopicExpression + " did not evaluate to a valid value (non empty String). Was: " + expressionValue);
throw new FlowableException("Expression " + jobTopicExpression + " did not evaluate to a valid value (non empty String). Was: " + expressionValue + ". For " + planItemInstanceEntity);
}

jobService.insertExternalWorkerJob(job);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ public void trigger(CommandContext commandContext, PlanItemInstanceEntity planIt
TaskService taskService = cmmnEngineConfiguration.getTaskServiceConfiguration().getTaskService();
List<TaskEntity> taskEntities = taskService.findTasksBySubScopeIdScopeType(planItemInstance.getId(), ScopeTypes.CMMN);
if (taskEntities == null || taskEntities.isEmpty()) {
throw new FlowableException("No task entity found for plan item instance " + planItemInstance.getId());
throw new FlowableException("No task entity found for " + planItemInstance);
}

// Should be only one
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public void execute(CommandContext commandContext, PlanItemInstanceEntity planIt
CmmnEngineConfiguration cmmnEngineConfiguration = CommandContextUtil.getCmmnEngineConfiguration(commandContext);
ProcessInstanceService processInstanceService = cmmnEngineConfiguration.getProcessInstanceService();
if (processInstanceService == null) {
throw new FlowableException("Could not start process instance: no " + ProcessInstanceService.class + " implementation found");
throw new FlowableException("Could not start process instance: no " + ProcessInstanceService.class + " implementation found for " + planItemInstanceEntity);
}

String externalRef = null;
Expand All @@ -81,7 +81,7 @@ public void execute(CommandContext commandContext, PlanItemInstanceEntity planIt
externalRef = processRef;
}
if (StringUtils.isEmpty(externalRef)) {
throw new FlowableException("Could not start process instance: no externalRef defined");
throw new FlowableException("Could not start process instance: no externalRef defined for " + planItemInstanceEntity);
}

Map<String, Object> inParametersMap = new HashMap<>();
Expand Down Expand Up @@ -147,7 +147,7 @@ public void trigger(CommandContext commandContext, PlanItemInstanceEntity planIt
}
if (!ReferenceTypes.PLAN_ITEM_CHILD_PROCESS.equals(planItemInstance.getReferenceType())) {
throw new FlowableException("Cannot trigger process task plan item instance : reference type '"
+ planItemInstance.getReferenceType() + "' not supported");
+ planItemInstance.getReferenceType() + "' not supported for " + planItemInstance);
}

// Need to be set before planning the complete operation
Expand Down Expand Up @@ -182,7 +182,7 @@ public void deleteChildEntity(CommandContext commandContext, DelegatePlanItemIns
delegatePlanItemInstance.setState(PlanItemInstanceState.TERMINATED); // This is not the regular termination, but the state still needs to be correct
deleteProcessInstance(commandContext, delegatePlanItemInstance);
} else {
throw new FlowableException("Can only delete a child entity for a plan item with reference type " + ReferenceTypes.PLAN_ITEM_CHILD_PROCESS);
throw new FlowableException("Can only delete a child entity for a plan item with reference type " + ReferenceTypes.PLAN_ITEM_CHILD_PROCESS + " for " + delegatePlanItemInstance);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public ScriptTaskActivityBehavior(ScriptServiceTask scriptTask) {
public void execute(CommandContext commandContext, PlanItemInstanceEntity planItemInstanceEntity) {
ScriptingEngines scriptingEngines = CommandContextUtil.getCmmnEngineConfiguration().getScriptingEngines();
if (scriptingEngines == null) {
throw new FlowableException("Could not execute script task instance: no scripting engines found.");
throw new FlowableException("Could not execute script task instance: no scripting engines found. For " + planItemInstanceEntity);
}
String scriptFormat = scriptTask.getScriptFormat() != null ? scriptTask.getScriptFormat() : ScriptingEngines.DEFAULT_SCRIPTING_LANGUAGE;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public SendEventActivityBehavior(SendEventServiceTask serviceTask) {
@Override
public void execute(CommandContext commandContext, PlanItemInstanceEntity planItemInstanceEntity) {

String key = getEventKey();
String key = getEventKey(planItemInstanceEntity);

EventRegistry eventRegistry = CommandContextUtil.getEventRegistry();

Expand Down Expand Up @@ -86,7 +86,7 @@ protected EventModel getEventModel(PlanItemInstanceEntity planItemInstanceEntity
}

if (eventModel == null) {
throw new FlowableException("No event model found for event key " + key);
throw new FlowableException("No event model found for event key " + key + " for " + planItemInstanceEntity);
}
return eventModel;
}
Expand Down Expand Up @@ -133,7 +133,7 @@ protected List<ChannelModel> getChannelModels(CommandContext commandContext, Pla
if (channelKeys.isEmpty()) {
if (!sendOnSystemChannel) {
// If the event is going to be send on the system channel then it is allowed to not define any other channels
throw new FlowableException("No channel keys configured");
throw new FlowableException("No channel keys configured for " + planItemInstanceEntity);
} else {
return Collections.emptyList();
}
Expand All @@ -152,11 +152,11 @@ protected List<ChannelModel> getChannelModels(CommandContext commandContext, Pla
return channelModels;
}

protected String getEventKey() {
protected String getEventKey(PlanItemInstanceEntity planItemInstanceEntity) {
if (StringUtils.isNotEmpty(serviceTask.getEventType())) {
return serviceTask.getEventType();
} else {
throw new FlowableException("No event key configured for " + serviceTask.getId());
throw new FlowableException("No event key configured for " + serviceTask.getId() + " for " + planItemInstanceEntity);
}
}

Expand Down
Loading

0 comments on commit cd50dac

Please sign in to comment.