Skip to content

Commit 615098c

Browse files
committed
[KOGITO-9838] Improving error message
1 parent 454122e commit 615098c

File tree

4 files changed

+88
-18
lines changed

4 files changed

+88
-18
lines changed

addons/common/rest-exception-handler/src/main/java/org/kie/kogito/resource/exceptions/BaseExceptionsHandler.java

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.kie.kogito.process.workitem.InvalidLifeCyclePhaseException;
3434
import org.kie.kogito.process.workitem.InvalidTransitionException;
3535
import org.kie.kogito.process.workitem.NotAuthorizedException;
36+
import org.kie.kogito.process.workitem.WorkItemExecutionException;
3637

3738
public abstract class BaseExceptionsHandler<T> {
3839

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

4950
private static class FunctionHolder<T, R> {
5051
private final Function<Exception, R> contentGenerator;
51-
private final Function<R, T> responseGenerator;
52+
private final Function<Exception, Function<R, T>> responseGenerator;
5253

53-
public FunctionHolder(Function<Exception, R> contentGenerator, Function<R, T> responseGenerator) {
54+
public FunctionHolder(Function<Exception, R> contentGenerator, Function<Exception, Function<R, T>> responseGenerator) {
5455
this.contentGenerator = contentGenerator;
5556
this.responseGenerator = responseGenerator;
5657
}
@@ -59,20 +60,20 @@ public Function<Exception, R> getContentGenerator() {
5960
return contentGenerator;
6061
}
6162

62-
public Function<R, T> getResponseGenerator() {
63+
public Function<Exception, Function<R, T>> getResponseGenerator() {
6364
return responseGenerator;
6465
}
6566
}
6667

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

6970
protected BaseExceptionsHandler() {
7071
mapper = new HashMap<>();
7172
mapper.put(InvalidLifeCyclePhaseException.class, new FunctionHolder<>(
72-
ex -> Collections.singletonMap(MESSAGE, ex.getMessage()), BaseExceptionsHandler.this::badRequest));
73+
ex -> Collections.singletonMap(MESSAGE, ex.getMessage()), ex -> BaseExceptionsHandler.this::badRequest));
7374

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

7778
mapper.put(NodeInstanceNotFoundException.class, new FunctionHolder<>(
7879
ex -> {
@@ -82,7 +83,7 @@ protected BaseExceptionsHandler() {
8283
response.put(PROCESS_INSTANCE_ID, exception.getProcessInstanceId());
8384
response.put(NODE_INSTANCE_ID, exception.getNodeInstanceId());
8485
return response;
85-
}, BaseExceptionsHandler.this::notFound));
86+
}, ex -> BaseExceptionsHandler.this::notFound));
8687

8788
mapper.put(NodeNotFoundException.class, new FunctionHolder<>(
8889
ex -> {
@@ -92,10 +93,10 @@ protected BaseExceptionsHandler() {
9293
response.put(PROCESS_INSTANCE_ID, exception.getProcessInstanceId());
9394
response.put(NODE_ID, exception.getNodeId());
9495
return response;
95-
}, BaseExceptionsHandler.this::notFound));
96+
}, ex -> BaseExceptionsHandler.this::notFound));
9697

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

100101
mapper.put(ProcessInstanceDuplicatedException.class, new FunctionHolder<>(
101102
ex -> {
@@ -104,7 +105,7 @@ protected BaseExceptionsHandler() {
104105
response.put(MESSAGE, exception.getMessage());
105106
response.put(PROCESS_INSTANCE_ID, exception.getProcessInstanceId());
106107
return response;
107-
}, BaseExceptionsHandler.this::conflict));
108+
}, ex -> BaseExceptionsHandler.this::conflict));
108109

109110
mapper.put(ProcessInstanceExecutionException.class, new FunctionHolder<>(
110111
ex -> {
@@ -114,7 +115,7 @@ protected BaseExceptionsHandler() {
114115
response.put(FAILED_NODE_ID, exception.getFailedNodeId());
115116
response.put(MESSAGE, exception.getErrorMessage());
116117
return response;
117-
}, BaseExceptionsHandler.this::internalError));
118+
}, ex -> BaseExceptionsHandler.this::internalError));
118119

119120
mapper.put(ProcessInstanceNotFoundException.class, new FunctionHolder<>(
120121
ex -> {
@@ -123,12 +124,12 @@ protected BaseExceptionsHandler() {
123124
response.put(MESSAGE, exception.getMessage());
124125
response.put(PROCESS_INSTANCE_ID, exception.getProcessInstanceId());
125126
return response;
126-
}, BaseExceptionsHandler.this::notFound));
127+
}, ex -> BaseExceptionsHandler.this::notFound));
127128

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

133134
mapper.put(VariableViolationException.class, new FunctionHolder<>(
134135
ex -> {
@@ -138,9 +139,28 @@ protected BaseExceptionsHandler() {
138139
response.put(PROCESS_INSTANCE_ID, exception.getProcessInstanceId());
139140
response.put(VARIABLE, exception.getVariableName());
140141
return response;
141-
}, BaseExceptionsHandler.this::badRequest));
142+
}, ex -> BaseExceptionsHandler.this::badRequest));
142143

143-
mapper.put(IllegalArgumentException.class, new FunctionHolder<>(ex -> Collections.singletonMap(MESSAGE, ex.getMessage()), BaseExceptionsHandler.this::badRequest));
144+
mapper.put(WorkItemExecutionException.class, new FunctionHolder<>(
145+
ex -> Map.of(MESSAGE, ex.getMessage()),
146+
ex -> fromErrorCode(((WorkItemExecutionException) ex).getErrorCode())));
147+
148+
mapper.put(IllegalArgumentException.class, new FunctionHolder<>(ex -> Collections.singletonMap(MESSAGE, ex.getMessage()), ex -> BaseExceptionsHandler.this::badRequest));
149+
}
150+
151+
private <R> Function<R, T> fromErrorCode(String errorCode) {
152+
switch (errorCode) {
153+
case "400":
154+
return this::badRequest;
155+
case "403":
156+
return this::forbidden;
157+
case "404":
158+
return this::notFound;
159+
case "409":
160+
return this::conflict;
161+
default:
162+
return this::internalError;
163+
}
144164
}
145165

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

162182
while (rootCause != null) {
163183
if (mapper.containsKey(rootCause.getClass())) {
@@ -167,6 +187,6 @@ public <R extends Exception, U> T mapException(R exception) {
167187
rootCause = rootCause.getCause();
168188
}
169189
}
170-
return holder.getResponseGenerator().apply(body);
190+
return holder.getResponseGenerator().apply(exception).apply(body);
171191
}
172192
}

addons/common/rest-exception-handler/src/test/java/org/kie/kogito/resource/exceptions/BaseExceptionHandlerTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.kie.kogito.process.workitem.InvalidLifeCyclePhaseException;
3131
import org.kie.kogito.process.workitem.InvalidTransitionException;
3232
import org.kie.kogito.process.workitem.NotAuthorizedException;
33+
import org.kie.kogito.process.workitem.WorkItemExecutionException;
3334
import org.mockito.Mock;
3435
import org.mockito.junit.jupiter.MockitoExtension;
3536

@@ -140,4 +141,14 @@ void testMapVariableViolationException() {
140141
"message"));
141142
assertThat(response).isEqualTo(badRequestResponse);
142143
}
144+
145+
@Test
146+
void testMapWorkItemExecutionException() {
147+
assertThat(tested.mapException(new WorkItemExecutionException("400", "message"))).isEqualTo(badRequestResponse);
148+
assertThat(tested.mapException(new WorkItemExecutionException("404", "message"))).isEqualTo(notFoundResponse);
149+
assertThat(tested.mapException(new WorkItemExecutionException("403", "message"))).isEqualTo(forbiddenResponse);
150+
assertThat(tested.mapException(new WorkItemExecutionException("409", "message"))).isEqualTo(conflictResponse);
151+
assertThat(tested.mapException(new WorkItemExecutionException("500", "message"))).isEqualTo(internalErrorResponse);
152+
assertThat(tested.mapException(new WorkItemExecutionException("One error code"))).isEqualTo(internalErrorResponse);
153+
}
143154
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.kie.kogito.resource.exceptions;
20+
21+
import javax.ws.rs.core.Response;
22+
import javax.ws.rs.ext.Provider;
23+
24+
import org.kie.kogito.process.workitem.WorkItemExecutionException;
25+
26+
@Provider
27+
public class WorkItemExecutionExceptionMapper extends BaseExceptionMapper<WorkItemExecutionException> {
28+
29+
@Override
30+
public Response toResponse(WorkItemExecutionException exception) {
31+
return exceptionsHandler.mapException(exception);
32+
}
33+
}

springboot/addons/rest-exception-handler/src/main/java/org/kie/kogito/resource/exceptions/springboot/ExceptionsHandler.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.kie.kogito.process.workitem.InvalidLifeCyclePhaseException;
2929
import org.kie.kogito.process.workitem.InvalidTransitionException;
3030
import org.kie.kogito.process.workitem.NotAuthorizedException;
31+
import org.kie.kogito.process.workitem.WorkItemExecutionException;
3132
import org.kie.kogito.resource.exceptions.BaseExceptionsHandler;
3233
import org.springframework.http.HttpStatus;
3334
import org.springframework.http.MediaType;
@@ -123,6 +124,11 @@ public ResponseEntity toResponse(WorkItemNotFoundException exception) {
123124
return mapException(exception);
124125
}
125126

127+
@ExceptionHandler(WorkItemExecutionException.class)
128+
public ResponseEntity toResponse(WorkItemExecutionException exception) {
129+
return mapException(exception);
130+
}
131+
126132
@ExceptionHandler(VariableViolationException.class)
127133
public ResponseEntity toResponse(VariableViolationException exception) {
128134
return mapException(exception);

0 commit comments

Comments
 (0)