Skip to content

Commit

Permalink
[KOGITO-9838] Improving error message
Browse files Browse the repository at this point in the history
  • Loading branch information
fjtirado committed Sep 26, 2023
1 parent 821650e commit 4ba9d81
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.kie.kogito.process.workitem.InvalidLifeCyclePhaseException;
import org.kie.kogito.process.workitem.InvalidTransitionException;
import org.kie.kogito.process.workitem.NotAuthorizedException;
import org.kie.kogito.process.workitem.WorkItemExecutionException;

public abstract class BaseExceptionsHandler<T> {

Expand All @@ -48,9 +49,9 @@ public abstract class BaseExceptionsHandler<T> {

private static class FunctionHolder<T, R> {
private final Function<Exception, R> contentGenerator;
private final Function<R, T> responseGenerator;
private final Function<Exception, Function<R, T>> responseGenerator;

public FunctionHolder(Function<Exception, R> contentGenerator, Function<R, T> responseGenerator) {
public FunctionHolder(Function<Exception, R> contentGenerator, Function<Exception, Function<R, T>> responseGenerator) {
this.contentGenerator = contentGenerator;
this.responseGenerator = responseGenerator;
}
Expand All @@ -59,20 +60,20 @@ public Function<Exception, R> getContentGenerator() {
return contentGenerator;
}

public Function<R, T> getResponseGenerator() {
public Function<Exception, Function<R, T>> getResponseGenerator() {
return responseGenerator;
}
}

private final FunctionHolder<T, Exception> defaultHolder = new FunctionHolder<>(ex -> ex, BaseExceptionsHandler.this::internalError);
private final FunctionHolder<T, Exception> defaultHolder = new FunctionHolder<>(ex -> ex, ex -> BaseExceptionsHandler.this::internalError);

protected BaseExceptionsHandler() {
mapper = new HashMap<>();
mapper.put(InvalidLifeCyclePhaseException.class, new FunctionHolder<>(
ex -> Collections.singletonMap(MESSAGE, ex.getMessage()), BaseExceptionsHandler.this::badRequest));
ex -> Collections.singletonMap(MESSAGE, ex.getMessage()), ex -> BaseExceptionsHandler.this::badRequest));

mapper.put(InvalidTransitionException.class, new FunctionHolder<>(
ex -> Collections.singletonMap(MESSAGE, ex.getMessage()), BaseExceptionsHandler.this::badRequest));
ex -> Collections.singletonMap(MESSAGE, ex.getMessage()), ex -> BaseExceptionsHandler.this::badRequest));

mapper.put(NodeInstanceNotFoundException.class, new FunctionHolder<>(
ex -> {
Expand All @@ -82,7 +83,7 @@ protected BaseExceptionsHandler() {
response.put(PROCESS_INSTANCE_ID, exception.getProcessInstanceId());
response.put(NODE_INSTANCE_ID, exception.getNodeInstanceId());
return response;
}, BaseExceptionsHandler.this::notFound));
}, ex -> BaseExceptionsHandler.this::notFound));

mapper.put(NodeNotFoundException.class, new FunctionHolder<>(
ex -> {
Expand All @@ -92,10 +93,10 @@ protected BaseExceptionsHandler() {
response.put(PROCESS_INSTANCE_ID, exception.getProcessInstanceId());
response.put(NODE_ID, exception.getNodeId());
return response;
}, BaseExceptionsHandler.this::notFound));
}, ex -> BaseExceptionsHandler.this::notFound));

mapper.put(NotAuthorizedException.class, new FunctionHolder<>(
ex -> Collections.singletonMap(MESSAGE, ex.getMessage()), BaseExceptionsHandler.this::forbidden));
ex -> Collections.singletonMap(MESSAGE, ex.getMessage()), ex -> BaseExceptionsHandler.this::forbidden));

mapper.put(ProcessInstanceDuplicatedException.class, new FunctionHolder<>(
ex -> {
Expand All @@ -104,7 +105,7 @@ protected BaseExceptionsHandler() {
response.put(MESSAGE, exception.getMessage());
response.put(PROCESS_INSTANCE_ID, exception.getProcessInstanceId());
return response;
}, BaseExceptionsHandler.this::conflict));
}, ex -> BaseExceptionsHandler.this::conflict));

mapper.put(ProcessInstanceExecutionException.class, new FunctionHolder<>(
ex -> {
Expand All @@ -114,7 +115,7 @@ protected BaseExceptionsHandler() {
response.put(FAILED_NODE_ID, exception.getFailedNodeId());
response.put(MESSAGE, exception.getErrorMessage());
return response;
}, BaseExceptionsHandler.this::internalError));
}, ex -> BaseExceptionsHandler.this::internalError));

mapper.put(ProcessInstanceNotFoundException.class, new FunctionHolder<>(
ex -> {
Expand All @@ -123,12 +124,12 @@ protected BaseExceptionsHandler() {
response.put(MESSAGE, exception.getMessage());
response.put(PROCESS_INSTANCE_ID, exception.getProcessInstanceId());
return response;
}, BaseExceptionsHandler.this::notFound));
}, ex -> BaseExceptionsHandler.this::notFound));

mapper.put(WorkItemNotFoundException.class, new FunctionHolder<>(ex -> {
WorkItemNotFoundException exception = (WorkItemNotFoundException) ex;
return Map.of(MESSAGE, exception.getMessage(), TASK_ID, exception.getWorkItemId());
}, BaseExceptionsHandler.this::notFound));
}, ex -> BaseExceptionsHandler.this::notFound));

mapper.put(VariableViolationException.class, new FunctionHolder<>(
ex -> {
Expand All @@ -138,9 +139,28 @@ protected BaseExceptionsHandler() {
response.put(PROCESS_INSTANCE_ID, exception.getProcessInstanceId());
response.put(VARIABLE, exception.getVariableName());
return response;
}, BaseExceptionsHandler.this::badRequest));
}, ex -> BaseExceptionsHandler.this::badRequest));

mapper.put(IllegalArgumentException.class, new FunctionHolder<>(ex -> Collections.singletonMap(MESSAGE, ex.getMessage()), BaseExceptionsHandler.this::badRequest));
mapper.put(WorkItemExecutionException.class, new FunctionHolder<>(
ex -> Map.of(MESSAGE, ex.getMessage()),
ex -> fromErrorCode(((WorkItemExecutionException) ex).getErrorCode())));

mapper.put(IllegalArgumentException.class, new FunctionHolder<>(ex -> Collections.singletonMap(MESSAGE, ex.getMessage()), ex -> BaseExceptionsHandler.this::badRequest));
}

private <R> Function<R, T> fromErrorCode(String errorCode) {
switch (errorCode) {
case "400":
return this::badRequest;
case "403":
return this::forbidden;
case "404":
return this::notFound;
case "409":
return this::conflict;
default:
return this::internalError;
}
}

protected abstract <R> T badRequest(R body);
Expand All @@ -156,8 +176,8 @@ protected BaseExceptionsHandler() {
public <R extends Exception, U> T mapException(R exception) {
FunctionHolder<T, U> holder = (FunctionHolder<T, U>) mapper.getOrDefault(exception.getClass(), defaultHolder);
U body = holder.getContentGenerator().apply(exception);
if (exception instanceof ProcessInstanceExecutionException) {
Throwable rootCause = ((ProcessInstanceExecutionException) exception).getCause();
if (exception instanceof ProcessInstanceExecutionException || exception instanceof WorkItemExecutionException) {
Throwable rootCause = exception.getCause();

while (rootCause != null) {
if (mapper.containsKey(rootCause.getClass())) {
Expand All @@ -167,6 +187,6 @@ public <R extends Exception, U> T mapException(R exception) {
rootCause = rootCause.getCause();
}
}
return holder.getResponseGenerator().apply(body);
return holder.getResponseGenerator().apply(exception).apply(body);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* 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.kie.kogito.resource.exceptions;

import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;

import org.kie.kogito.process.workitem.WorkItemExecutionException;

@Provider
public class WorkItemExecutionExceptionMapper extends BaseExceptionMapper<WorkItemExecutionException> {

@Override
public Response toResponse(WorkItemExecutionException exception) {
return exceptionsHandler.mapException(exception);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.kie.kogito.process.workitem.InvalidLifeCyclePhaseException;
import org.kie.kogito.process.workitem.InvalidTransitionException;
import org.kie.kogito.process.workitem.NotAuthorizedException;
import org.kie.kogito.process.workitem.WorkItemExecutionException;
import org.kie.kogito.resource.exceptions.BaseExceptionsHandler;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
Expand Down Expand Up @@ -123,6 +124,11 @@ public ResponseEntity toResponse(WorkItemNotFoundException exception) {
return mapException(exception);
}

@ExceptionHandler(WorkItemExecutionException.class)
public ResponseEntity toResponse(WorkItemExecutionException exception) {
return mapException(exception);
}

@ExceptionHandler(VariableViolationException.class)
public ResponseEntity toResponse(VariableViolationException exception) {
return mapException(exception);
Expand Down

0 comments on commit 4ba9d81

Please sign in to comment.