Skip to content

Commit 658665a

Browse files
committed
Merge remote-tracking branch 'origin/master'
2 parents 742c1fa + f7874e0 commit 658665a

18 files changed

+284
-69
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ to see what's needed to create a Servlet with a schema.
5454

5555
## Using the latest development build
5656

57-
Snapshot versions of the current `master` branch are availble on JFrog. Check the next snapshot version in
57+
Snapshot versions of the current `master` branch are available on JFrog. Check the next snapshot version in
5858
[gradle.properties](https://github.com/graphql-java-kickstart/graphql-java-servlet/blob/master/gradle.properties).
5959

6060
### Build with Gradle

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ dependencies {
3333
compile 'org.slf4j:slf4j-api:1.7.21'
3434

3535
// Useful utilities
36-
compile 'com.google.guava:guava:20.0'
36+
compile 'com.google.guava:guava:24.1.1-jre'
3737

3838
// Unit testing
3939
testCompile "org.codehaus.groovy:groovy-all:2.4.1"

examples/osgi/apache-karaf-feature/pom.xml

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,37 @@
1212
<artifactId>graphql-java-servlet-osgi-examples-karaf-feature</artifactId>
1313
<packaging>feature</packaging>
1414

15-
<dependencies>
15+
<properties>
16+
<jackson.version>2.9.8</jackson.version>
17+
</properties>
18+
1619

20+
21+
<dependencies>
1722
<dependency>
1823
<groupId>com.fasterxml.jackson.core</groupId>
1924
<artifactId>jackson-core</artifactId>
20-
<version>2.8.11</version>
25+
<version>${jackson.version}</version>
2126
</dependency>
2227
<dependency>
2328
<groupId>com.fasterxml.jackson.core</groupId>
2429
<artifactId>jackson-annotations</artifactId>
25-
<version>2.8.11</version>
30+
<version>${jackson.version}</version>
2631
</dependency>
2732
<dependency>
2833
<groupId>com.fasterxml.jackson.core</groupId>
2934
<artifactId>jackson-databind</artifactId>
30-
<version>2.8.11</version>
35+
<version>${jackson.version}</version>
3136
</dependency>
3237
<dependency>
3338
<groupId>com.fasterxml.jackson.datatype</groupId>
3439
<artifactId>jackson-datatype-jdk8</artifactId>
35-
<version>2.8.11</version>
40+
<version>${jackson.version}</version>
3641
</dependency>
3742
<dependency>
3843
<groupId>com.google.guava</groupId>
3944
<artifactId>guava</artifactId>
40-
<version>20.0</version>
45+
<version>24.1.1-jre</version>
4146
</dependency>
4247
<dependency>
4348
<groupId>commons-fileupload</groupId>

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ version = 7.3.0-SNAPSHOT
22
group = com.graphql-java-kickstart
33

44
LIB_GRAPHQL_JAVA_VER = 11.0
5-
LIB_JACKSON_VER = 2.9.7
5+
LIB_JACKSON_VER = 2.9.8

src/main/java/graphql/servlet/AbstractGraphQLHttpServlet.java

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ public abstract class AbstractGraphQLHttpServlet extends HttpServlet implements
7373
@Deprecated
7474
protected abstract GraphQLObjectMapper getGraphQLObjectMapper();
7575

76+
/**
77+
* @deprecated override {@link #getConfiguration()} instead
78+
*/
79+
@Deprecated
80+
protected abstract GraphQLBatchExecutionHandlerFactory getBatchExecutionHandlerFactory();
81+
7682
/**
7783
* @deprecated override {@link #getConfiguration()} instead
7884
*/
@@ -85,6 +91,7 @@ protected GraphQLConfiguration getConfiguration() {
8591
.with(getGraphQLObjectMapper())
8692
.with(isAsyncServletMode())
8793
.with(listeners)
94+
.with(getBatchExecutionHandlerFactory())
8895
.build();
8996
}
9097

@@ -113,6 +120,7 @@ public void init(ServletConfig servletConfig) {
113120
GraphQLInvocationInputFactory invocationInputFactory = configuration.getInvocationInputFactory();
114121
GraphQLObjectMapper graphQLObjectMapper = configuration.getObjectMapper();
115122
GraphQLQueryInvoker queryInvoker = configuration.getQueryInvoker();
123+
GraphQLBatchExecutionHandlerFactory batchExecutionHandlerFactory = configuration.getBatchExecutionHandlerFactory();
116124

117125
String path = request.getPathInfo();
118126
if (path == null) {
@@ -125,7 +133,7 @@ public void init(ServletConfig servletConfig) {
125133
if (query != null) {
126134

127135
if (isBatchedQuery(query)) {
128-
queryBatched(queryInvoker, graphQLObjectMapper, invocationInputFactory.createReadOnly(graphQLObjectMapper.readBatchedGraphQLRequest(query), request, response), response);
136+
queryBatched(batchExecutionHandlerFactory, queryInvoker, graphQLObjectMapper, invocationInputFactory.createReadOnly(graphQLObjectMapper.readBatchedGraphQLRequest(query), request, response), response);
129137
} else {
130138
final Map<String, Object> variables = new HashMap<>();
131139
if (request.getParameter("variables") != null) {
@@ -147,6 +155,7 @@ public void init(ServletConfig servletConfig) {
147155
GraphQLInvocationInputFactory invocationInputFactory = configuration.getInvocationInputFactory();
148156
GraphQLObjectMapper graphQLObjectMapper = configuration.getObjectMapper();
149157
GraphQLQueryInvoker queryInvoker = configuration.getQueryInvoker();
158+
GraphQLBatchExecutionHandlerFactory batchExecutionHandlerFactory = configuration.getBatchExecutionHandlerFactory();
150159

151160
try {
152161
if (APPLICATION_GRAPHQL.equals(request.getContentType())) {
@@ -181,7 +190,7 @@ public void init(ServletConfig servletConfig) {
181190
GraphQLBatchedInvocationInput invocationInput =
182191
invocationInputFactory.create(graphQLRequests, request, response);
183192
invocationInput.getContext().setParts(fileItems);
184-
queryBatched(queryInvoker, graphQLObjectMapper, invocationInput, response);
193+
queryBatched(batchExecutionHandlerFactory, queryInvoker, graphQLObjectMapper, invocationInput, response);
185194
return;
186195
} else {
187196
GraphQLRequest graphQLRequest;
@@ -207,7 +216,7 @@ public void init(ServletConfig servletConfig) {
207216
InputStream inputStream = asMarkableInputStream(request.getInputStream());
208217

209218
if (isBatchedQuery(inputStream)) {
210-
queryBatched(queryInvoker, graphQLObjectMapper, invocationInputFactory.create(graphQLObjectMapper.readBatchedGraphQLRequest(inputStream), request, response), response);
219+
queryBatched(batchExecutionHandlerFactory, queryInvoker, graphQLObjectMapper, invocationInputFactory.create(graphQLObjectMapper.readBatchedGraphQLRequest(inputStream), request, response), response);
211220
} else {
212221
query(queryInvoker, graphQLObjectMapper, invocationInputFactory.create(graphQLObjectMapper.readGraphQLRequest(inputStream), request, response), response);
213222
}
@@ -364,21 +373,13 @@ private void query(GraphQLQueryInvoker queryInvoker, GraphQLObjectMapper graphQL
364373
}
365374
}
366375

367-
private void queryBatched(GraphQLQueryInvoker queryInvoker, GraphQLObjectMapper graphQLObjectMapper, GraphQLBatchedInvocationInput invocationInput, HttpServletResponse resp) throws Exception {
376+
private void queryBatched(GraphQLBatchExecutionHandlerFactory batchInputHandlerFactory, GraphQLQueryInvoker queryInvoker, GraphQLObjectMapper graphQLObjectMapper, GraphQLBatchedInvocationInput invocationInput, HttpServletResponse resp) throws Exception {
368377
resp.setContentType(APPLICATION_JSON_UTF8);
369378
resp.setStatus(STATUS_OK);
370379

371380
Writer respWriter = resp.getWriter();
372-
respWriter.write('[');
373-
374-
queryInvoker.query(invocationInput, (result, hasNext) -> {
375-
respWriter.write(graphQLObjectMapper.serializeResultAsJson(result));
376-
if (hasNext) {
377-
respWriter.write(',');
378-
}
379-
});
380381

381-
respWriter.write(']');
382+
queryInvoker.query(invocationInput, batchInputHandlerFactory.getBatchHandler(respWriter, graphQLObjectMapper));
382383
}
383384

384385
private <R> List<R> runListeners(Function<? super GraphQLServletListener, R> action) {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package graphql.servlet;
2+
3+
import graphql.ExecutionInput;
4+
import graphql.ExecutionResult;
5+
6+
import java.util.function.BiFunction;
7+
8+
/**
9+
* @author Andrew Potter
10+
*/
11+
public interface BatchExecutionHandler {
12+
/**
13+
* Allows separating the logic of handling batch queries from how each individual query is resolved.
14+
* @param batchedInvocationInput the batch query input
15+
* @param queryFunction Function to produce query results.
16+
*/
17+
void handleBatch(GraphQLBatchedInvocationInput batchedInvocationInput, BiFunction<GraphQLInvocationInput, ExecutionInput, ExecutionResult> queryFunction);
18+
}
19+
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package graphql.servlet;
2+
3+
import graphql.ExecutionInput;
4+
import graphql.ExecutionResult;
5+
6+
import java.io.IOException;
7+
import java.io.Writer;
8+
import java.util.Iterator;
9+
import java.util.function.BiFunction;
10+
11+
public class DefaultGraphQLBatchExecutionHandlerFactory implements GraphQLBatchExecutionHandlerFactory {
12+
@Override
13+
public BatchExecutionHandler getBatchHandler(Writer respWriter, GraphQLObjectMapper graphQLObjectMapper) {
14+
return new DefaultGraphQLBatchExecutionHandler(respWriter, graphQLObjectMapper);
15+
}
16+
17+
private class DefaultGraphQLBatchExecutionHandler implements BatchExecutionHandler {
18+
19+
private final Writer respWriter;
20+
21+
private final GraphQLObjectMapper graphQLObjectMapper;
22+
23+
private DefaultGraphQLBatchExecutionHandler(Writer respWriter, GraphQLObjectMapper graphQLObjectMapper) {
24+
this.respWriter = respWriter;
25+
this.graphQLObjectMapper = graphQLObjectMapper;
26+
}
27+
28+
@Override
29+
public void handleBatch(GraphQLBatchedInvocationInput batchedInvocationInput, BiFunction<GraphQLInvocationInput, ExecutionInput,
30+
ExecutionResult> queryFunction) {
31+
Iterator<ExecutionInput> executionInputIterator = batchedInvocationInput.getExecutionInputs().iterator();
32+
try {
33+
respWriter.write("[");
34+
while (executionInputIterator.hasNext()) {
35+
ExecutionResult result = queryFunction.apply(batchedInvocationInput, executionInputIterator.next());
36+
respWriter.write(graphQLObjectMapper.serializeResultAsJson(result));
37+
if (executionInputIterator.hasNext()) {
38+
respWriter.write(",");
39+
}
40+
}
41+
respWriter.write("]");
42+
} catch (IOException e) {
43+
throw new RuntimeException(e);
44+
}
45+
}
46+
}
47+
}

src/main/java/graphql/servlet/DefaultGraphQLServlet.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ protected GraphQLObjectMapper getGraphQLObjectMapper() {
2525
return GraphQLObjectMapper.newBuilder().build();
2626
}
2727

28+
@Override
29+
protected GraphQLBatchExecutionHandlerFactory getBatchExecutionHandlerFactory() {
30+
return null;
31+
}
32+
2833
@Override
2934
protected boolean isAsyncServletMode() {
3035
return false;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package graphql.servlet;
2+
3+
import java.io.Writer;
4+
5+
/**
6+
* Interface to allow customization of how batched queries are handled.
7+
*/
8+
public interface GraphQLBatchExecutionHandlerFactory {
9+
/**
10+
* Produces an BatchExecutionHandler instance for a specific response. Can maintain state across each request within a batch.
11+
* @param respWriter to send the response back
12+
* @param graphQLObjectMapper to serialize results.
13+
* @return a handler instance
14+
*/
15+
BatchExecutionHandler getBatchHandler(Writer respWriter, GraphQLObjectMapper graphQLObjectMapper);
16+
}

src/main/java/graphql/servlet/GraphQLConfiguration.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public class GraphQLConfiguration {
1313
private GraphQLInvocationInputFactory invocationInputFactory;
1414
private GraphQLQueryInvoker queryInvoker;
1515
private GraphQLObjectMapper objectMapper;
16+
private GraphQLBatchExecutionHandlerFactory batchExecutionHandlerFactory;
1617
private List<GraphQLServletListener> listeners;
1718
private boolean asyncServletModeEnabled;
1819
private Executor asyncExecutor;
@@ -30,10 +31,11 @@ public static GraphQLConfiguration.Builder with(GraphQLInvocationInputFactory in
3031
return new Builder(invocationInputFactory);
3132
}
3233

33-
private GraphQLConfiguration(GraphQLInvocationInputFactory invocationInputFactory, GraphQLQueryInvoker queryInvoker, GraphQLObjectMapper objectMapper, List<GraphQLServletListener> listeners, boolean asyncServletModeEnabled, Executor asyncExecutor, long subscriptionTimeout) {
34+
private GraphQLConfiguration(GraphQLInvocationInputFactory invocationInputFactory, GraphQLQueryInvoker queryInvoker, GraphQLObjectMapper objectMapper, GraphQLBatchExecutionHandlerFactory batchExecutionHandlerFactory, List<GraphQLServletListener> listeners, boolean asyncServletModeEnabled, Executor asyncExecutor, long subscriptionTimeout) {
3435
this.invocationInputFactory = invocationInputFactory;
3536
this.queryInvoker = queryInvoker;
3637
this.objectMapper = objectMapper;
38+
this.batchExecutionHandlerFactory = batchExecutionHandlerFactory;
3739
this.listeners = listeners;
3840
this.asyncServletModeEnabled = asyncServletModeEnabled;
3941
this.asyncExecutor = asyncExecutor;
@@ -52,6 +54,10 @@ public GraphQLObjectMapper getObjectMapper() {
5254
return objectMapper;
5355
}
5456

57+
public GraphQLBatchExecutionHandlerFactory getBatchExecutionHandlerFactory() {
58+
return batchExecutionHandlerFactory;
59+
}
60+
5561
public List<GraphQLServletListener> getListeners() {
5662
return new ArrayList<>(listeners);
5763
}
@@ -82,6 +88,7 @@ public static class Builder {
8288
private GraphQLInvocationInputFactory invocationInputFactory;
8389
private GraphQLQueryInvoker queryInvoker = GraphQLQueryInvoker.newBuilder().build();
8490
private GraphQLObjectMapper objectMapper = GraphQLObjectMapper.newBuilder().build();
91+
private GraphQLBatchExecutionHandlerFactory graphQLBatchExecutionHandlerFactory = new DefaultGraphQLBatchExecutionHandlerFactory();
8592
private List<GraphQLServletListener> listeners = new ArrayList<>();
8693
private boolean asyncServletModeEnabled = false;
8794
private Executor asyncExecutor = Executors.newCachedThreadPool(new GraphQLThreadFactory());
@@ -109,6 +116,13 @@ public Builder with(GraphQLObjectMapper objectMapper) {
109116
return this;
110117
}
111118

119+
public Builder with(GraphQLBatchExecutionHandlerFactory batchExecutionHandlerFactory) {
120+
if (batchExecutionHandlerFactory != null) {
121+
this.graphQLBatchExecutionHandlerFactory = batchExecutionHandlerFactory;
122+
}
123+
return this;
124+
}
125+
112126
public Builder with(List<GraphQLServletListener> listeners) {
113127
if (listeners != null) {
114128
this.listeners = listeners;
@@ -148,6 +162,7 @@ public GraphQLConfiguration build() {
148162
this.invocationInputFactory != null ? this.invocationInputFactory : invocationInputFactoryBuilder.build(),
149163
queryInvoker,
150164
objectMapper,
165+
graphQLBatchExecutionHandlerFactory,
151166
listeners,
152167
asyncServletModeEnabled,
153168
asyncExecutor,

0 commit comments

Comments
 (0)