Skip to content

Commit 7925244

Browse files
committed
Rework listeners to allow context between before/after.
1 parent 94c5e1a commit 7925244

File tree

6 files changed

+104
-92
lines changed

6 files changed

+104
-92
lines changed

README.md

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -56,42 +56,52 @@ GraphQLServlet servlet = new SimpleGraphQLServlet(schema, executionStrategy);
5656
GraphQLServlet servlet = new SimpleGraphQLServlet(schema, executionStrategy, operationListeners, servletListeners);
5757
```
5858

59-
## Operation and Servlet Listeners
59+
## Servlet Listeners
6060

61-
You can also add [operation listeners](https://github.com/graphql-java/graphql-java-servlet/blob/master/src/main/java/graphql/servlet/GraphQLOperationListener.java) and [servlet listeners](https://github.com/graphql-java/graphql-java-servlet/blob/master/src/main/java/graphql/servlet/GraphQLServletListener.java) to an existing servlet.
62-
These listeners provide hooks into query execution (before, on success, and on failure) and servlet execution (before, on error, and finally):
61+
You can also add [servlet listeners](https://github.com/graphql-java/graphql-java-servlet/blob/master/src/main/java/graphql/servlet/GraphQLServletListener.java) to an existing servlet.
62+
These listeners provide hooks into query execution (before, success, failure, and finally) and servlet execution (before, success, error, and finally):
6363
```java
64-
servlet.addOperationListener(new GraphQLOperationListener() {
64+
servlet.addListener(new GraphQLServletListener() {
6565
@Override
66-
void beforeGraphQLOperation(GraphQLContext context, String operationName, String query, Map<String, Object> variables) {
66+
GraphQLServletListener.RequestCallback onRequest(HttpServletRequest request, HttpServletResponse response) {
6767

68-
}
68+
return new GraphQLServletListener.RequestCallback() {
69+
@Override
70+
void onSuccess(HttpServletRequest request, HttpServletResponse response) {
6971

70-
@Override
71-
void onSuccessfulGraphQLOperation(GraphQLContext context, String operationName, String query, Map<String, Object> variables, Object data) {
72+
}
7273

73-
}
74+
@Override
75+
void onError(HttpServletRequest request, HttpServletResponse response, Throwable throwable) {
7476

75-
@Override
76-
void onFailedGraphQLOperation(GraphQLContext context, String operationName, String query, Map<String, Object> variables, Object data, List<GraphQLError> errors) {
77+
}
78+
79+
@Override
80+
void onFinally(HttpServletRequest request, HttpServletResponse response) {
7781

82+
}
83+
}
7884
}
79-
})
8085

81-
servlet.addServletListener(new GraphQLServletListener() {
8286
@Override
83-
void onStart(HttpServletRequest request, HttpServletResponse response) {
87+
GraphQLServletListener.OperationCallback onOperation(GraphQLContext context, String operationName, String query, Map<String, Object> variables) {
8488

85-
}
89+
return new GraphQLServletListener.OperationCallback() {
90+
@Override
91+
void onSuccess(GraphQLContext context, String operationName, String query, Map<String, Object> variables, Object data) {
8692

87-
@Override
88-
void onError(HttpServletRequest request, HttpServletResponse response, Throwable throwable) {
93+
}
8994

90-
}
95+
@Override
96+
void onError(GraphQLContext context, String operationName, String query, Map<String, Object> variables, Object data, List<GraphQLError> errors) {
9197

92-
@Override
93-
void onFinally(HttpServletRequest request, HttpServletResponse response) {
98+
}
99+
100+
@Override
101+
void onFinally(GraphQLContext context, String operationName, String query, Map<String, Object> variables, Object data) {
94102

103+
}
104+
}
95105
}
96106
})
97107
```

src/main/java/graphql/servlet/GraphQLOperationListener.java

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/main/java/graphql/servlet/GraphQLServlet.java

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,15 @@
4949
import java.security.AccessController;
5050
import java.security.PrivilegedAction;
5151
import java.util.ArrayList;
52+
import java.util.Collections;
5253
import java.util.HashMap;
5354
import java.util.List;
5455
import java.util.Map;
56+
import java.util.Objects;
5557
import java.util.Optional;
5658
import java.util.function.BiConsumer;
5759
import java.util.function.Consumer;
60+
import java.util.function.Function;
5861
import java.util.stream.Collectors;
5962

6063
/**
@@ -77,20 +80,18 @@ public abstract class GraphQLServlet extends HttpServlet implements Servlet, Gra
7780
protected abstract Instrumentation getInstrumentation();
7881
protected abstract Map<String, Object> transformVariables(GraphQLSchema schema, String query, Map<String, Object> variables);
7982

80-
private final List<GraphQLOperationListener> operationListeners;
81-
private final List<GraphQLServletListener> servletListeners;
83+
private final List<GraphQLServletListener> listeners;
8284
private final ServletFileUpload fileUpload;
8385

8486
private final RequestHandler getHandler;
8587
private final RequestHandler postHandler;
8688

8789
public GraphQLServlet() {
88-
this(null, null, null);
90+
this(null, null);
8991
}
9092

91-
public GraphQLServlet(List<GraphQLOperationListener> operationListeners, List<GraphQLServletListener> servletListeners, FileItemFactory fileItemFactory) {
92-
this.operationListeners = operationListeners != null ? new ArrayList<>(operationListeners) : new ArrayList<>();
93-
this.servletListeners = servletListeners != null ? new ArrayList<>(servletListeners) : new ArrayList<>();
93+
public GraphQLServlet(List<GraphQLServletListener> listeners, FileItemFactory fileItemFactory) {
94+
this.listeners = listeners != null ? new ArrayList<>(listeners) : new ArrayList<>();
9495
this.fileUpload = new ServletFileUpload(fileItemFactory != null ? fileItemFactory : new DiskFileItemFactory());
9596

9697
this.getHandler = (request, response) -> {
@@ -188,20 +189,12 @@ public GraphQLServlet(List<GraphQLOperationListener> operationListeners, List<Gr
188189
};
189190
}
190191

191-
public void addOperationListener(GraphQLOperationListener operationListener) {
192-
operationListeners.add(operationListener);
192+
public void addListener(GraphQLServletListener servletListener) {
193+
listeners.add(servletListener);
193194
}
194195

195-
public void removeOperationListener(GraphQLOperationListener operationListener) {
196-
operationListeners.remove(operationListener);
197-
}
198-
199-
public void addServletListener(GraphQLServletListener servletListener) {
200-
servletListeners.add(servletListener);
201-
}
202-
203-
public void removeServletListener(GraphQLServletListener servletListener) {
204-
servletListeners.remove(servletListener);
196+
public void removeListener(GraphQLServletListener servletListener) {
197+
listeners.remove(servletListener);
205198
}
206199

207200
@Override
@@ -225,16 +218,18 @@ public String executeQuery(String query) {
225218
}
226219

227220
private void doRequest(HttpServletRequest request, HttpServletResponse response, RequestHandler handler) {
221+
222+
List<GraphQLServletListener.RequestCallback> requestCallbacks = runListeners(l -> l.onRequest(request, response));
223+
228224
try {
229-
runListeners(servletListeners, l -> l.onStart(request, response));
230225
handler.handle(request, response);
231-
226+
runCallbacks(requestCallbacks, c -> c.onSuccess(request, response));
232227
} catch (Throwable t) {
233228
response.setStatus(500);
234229
log.error("Error executing GraphQL request!", t);
235-
runListeners(servletListeners, l -> l.onError(request, response, t));
230+
runCallbacks(requestCallbacks, c -> c.onError(request, response, t));
236231
} finally {
237-
runListeners(servletListeners, l -> l.onFinally(request, response));
232+
runCallbacks(requestCallbacks, c -> c.onFinally(request, response));
238233
}
239234
}
240235

@@ -276,7 +271,7 @@ private void query(String query, String operationName, Map<String, Object> varia
276271
return null;
277272
});
278273
} else {
279-
runListeners(operationListeners, l -> runListener(l, it -> it.beforeGraphQLOperation(context, operationName, query, variables)));
274+
List<GraphQLServletListener.OperationCallback> operationCallbacks = runListeners(l -> l.onOperation(context, operationName, query, variables));
280275

281276
final ExecutionResult executionResult = newGraphQL(schema).execute(query, operationName, context, transformVariables(schema, query, variables));
282277
final List<GraphQLError> errors = executionResult.getErrors();
@@ -289,10 +284,12 @@ private void query(String query, String operationName, Map<String, Object> varia
289284
resp.getWriter().write(response);
290285

291286
if(errorsPresent(errors)) {
292-
runListeners(operationListeners, l -> l.onFailedGraphQLOperation(context, operationName, query, variables, data, errors));
287+
runCallbacks(operationCallbacks, c -> c.onError(context, operationName, query, variables, data, errors));
293288
} else {
294-
runListeners(operationListeners, l -> l.onSuccessfulGraphQLOperation(context, operationName, query, variables, data));
289+
runCallbacks(operationCallbacks, c -> c.onSuccess(context, operationName, query, variables, data));
295290
}
291+
292+
runCallbacks(operationCallbacks, c -> c.onFinally(context, operationName, query, variables, data));
296293
}
297294
}
298295

@@ -333,21 +330,38 @@ protected boolean isClientError(GraphQLError error) {
333330
return error instanceof InvalidSyntaxError || error instanceof ValidationError;
334331
}
335332

336-
private <T> void runListeners(List<T> listeners, Consumer<? super T> action) {
337-
if (listeners != null) {
338-
listeners.forEach(l -> runListener(l, action));
333+
private <R> List<R> runListeners(Function<? super GraphQLServletListener, R> action) {
334+
if (listeners == null) {
335+
return Collections.emptyList();
339336
}
337+
338+
return listeners.stream()
339+
.map(listener -> {
340+
try {
341+
return action.apply(listener);
342+
} catch (Throwable t) {
343+
log.error("Error running listener: {}", listener, t);
344+
return null;
345+
}
346+
})
347+
.filter(Objects::nonNull)
348+
.collect(Collectors.toList());
349+
}
350+
351+
private <T> void runCallbacks(List<T> callbacks, Consumer<T> action) {
352+
callbacks.forEach(callback -> {
353+
try {
354+
action.accept(callback);
355+
} catch (Throwable t) {
356+
log.error("Error running callback: {}", callback, t);
357+
}
358+
});
340359
}
341360

342361
/**
343362
* Don't let listener errors escape to the client.
344363
*/
345-
private <T> void runListener(T listener, Consumer<? super T> action) {
346-
try {
347-
action.accept(listener);
348-
} catch (Throwable t) {
349-
log.error("Error running listener: {}", listener.getClass().getName(), t);
350-
}
364+
private <T, R> void runListener(T listener, Function<? super T, ? super R> action) {
351365
}
352366

353367
protected static class VariablesDeserializer extends JsonDeserializer<Map<String, Object>> {

src/main/java/graphql/servlet/GraphQLServletListener.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,33 @@
1414
*/
1515
package graphql.servlet;
1616

17+
import graphql.GraphQLError;
18+
1719
import javax.servlet.http.HttpServletRequest;
1820
import javax.servlet.http.HttpServletResponse;
21+
import java.util.List;
22+
import java.util.Map;
1923

2024
/**
2125
* @author Andrew Potter
2226
*/
2327
public interface GraphQLServletListener {
24-
default void onStart(HttpServletRequest request, HttpServletResponse response) {}
25-
default void onError(HttpServletRequest request, HttpServletResponse response, Throwable throwable) {}
26-
default void onFinally(HttpServletRequest request, HttpServletResponse response) {}
28+
default RequestCallback onRequest(HttpServletRequest request, HttpServletResponse response) {
29+
return null;
30+
}
31+
default OperationCallback onOperation(GraphQLContext context, String operationName, String query, Map<String, Object> variables) {
32+
return null;
33+
}
34+
35+
interface RequestCallback {
36+
default void onSuccess(HttpServletRequest request, HttpServletResponse response) {}
37+
default void onError(HttpServletRequest request, HttpServletResponse response, Throwable throwable) {}
38+
default void onFinally(HttpServletRequest request, HttpServletResponse response) {}
39+
}
40+
41+
interface OperationCallback {
42+
default void onSuccess(GraphQLContext context, String operationName, String query, Map<String, Object> variables, Object data) {}
43+
default void onError(GraphQLContext context, String operationName, String query, Map<String, Object> variables, Object data, List<GraphQLError> errors) {}
44+
default void onFinally(GraphQLContext context, String operationName, String query, Map<String, Object> variables, Object data) {}
45+
}
2746
}

src/main/java/graphql/servlet/OsgiGraphQLServlet.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -170,13 +170,4 @@ protected Instrumentation getInstrumentation() {
170170
protected Map<String, Object> transformVariables(GraphQLSchema schema, String query, Map<String, Object> variables) {
171171
return new GraphQLVariables(schema, query, variables);
172172
}
173-
174-
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policyOption = ReferencePolicyOption.GREEDY)
175-
public void bindOperationListener(GraphQLOperationListener listener) {
176-
addOperationListener(listener);
177-
}
178-
179-
public void unbindOperationListener(GraphQLOperationListener listener) {
180-
removeOperationListener(listener);
181-
}
182173
}

src/test/groovy/graphql/servlet/GraphQLServletSpec.groovy

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package graphql.servlet
1616

1717
import com.fasterxml.jackson.databind.ObjectMapper
18+
import graphql.GraphQLError
1819
import graphql.Scalars
1920
import graphql.execution.SimpleExecutionStrategy
2021
import graphql.schema.DataFetcher
@@ -25,6 +26,9 @@ import org.springframework.mock.web.MockHttpServletResponse
2526
import spock.lang.Shared
2627
import spock.lang.Specification
2728

29+
import javax.servlet.http.HttpServletRequest
30+
import javax.servlet.http.HttpServletResponse
31+
2832
/**
2933
* @author Andrew Potter
3034
*/

0 commit comments

Comments
 (0)