Skip to content

Commit 4380611

Browse files
committed
Extracted http request handler
1 parent 30a6be4 commit 4380611

30 files changed

+1204
-677
lines changed

build.gradle

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ plugins {
1111
id "com.jfrog.bintray" version "1.8.4"
1212
id "com.jfrog.artifactory" version "4.8.1"
1313
id 'net.researchgate.release' version '2.7.0'
14+
id 'io.franzbecker.gradle-lombok' version '3.1.0'
1415
}
1516

1617
apply plugin: 'java'
@@ -25,10 +26,6 @@ repositories {
2526
mavenCentral()
2627
}
2728

28-
configurations.all {
29-
exclude group:"org.projectlombok", module: "lombok"
30-
}
31-
3229
dependencies {
3330
compile 'org.slf4j:slf4j-api:1.7.21'
3431

@@ -210,3 +207,7 @@ idea {
210207
wrapper {
211208
gradleVersion = '4.10.3'
212209
}
210+
211+
lombok {
212+
version = '1.18.10'
213+
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
#Thu Jun 20 12:32:36 CEST 2019
1+
#Thu Nov 14 18:53:34 CET 2019
2+
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip
23
distributionBase=GRADLE_USER_HOME
34
distributionPath=wrapper/dists
4-
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists
6-
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip
6+
zipStoreBase=GRADLE_USER_HOME

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

Lines changed: 403 additions & 530 deletions
Large diffs are not rendered by default.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package graphql.servlet;
2+
3+
import static graphql.servlet.HttpRequestHandler.APPLICATION_JSON_UTF8;
4+
import static graphql.servlet.HttpRequestHandler.STATUS_OK;
5+
6+
import graphql.ExecutionResult;
7+
import graphql.servlet.core.GraphQLObjectMapper;
8+
import java.io.IOException;
9+
import java.io.Writer;
10+
import java.util.Iterator;
11+
import java.util.List;
12+
import javax.servlet.http.HttpServletRequest;
13+
import javax.servlet.http.HttpServletResponse;
14+
import lombok.RequiredArgsConstructor;
15+
16+
@RequiredArgsConstructor
17+
class BatchedQueryResponseWriter implements QueryResponseWriter {
18+
19+
private final List<ExecutionResult> results;
20+
private final GraphQLObjectMapper graphQLObjectMapper;
21+
22+
@Override
23+
public void write(HttpServletRequest request, HttpServletResponse response) throws IOException {
24+
response.setContentType(APPLICATION_JSON_UTF8);
25+
response.setStatus(STATUS_OK);
26+
27+
Writer writer = response.getWriter();
28+
Iterator<ExecutionResult> executionInputIterator = results.iterator();
29+
writer.write("[");
30+
while (executionInputIterator.hasNext()) {
31+
String result = graphQLObjectMapper.serializeResultAsJson(executionInputIterator.next());
32+
writer.write(result);
33+
if (executionInputIterator.hasNext()) {
34+
writer.write(",");
35+
}
36+
}
37+
writer.write("]");
38+
}
39+
40+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package graphql.servlet;
2+
3+
import graphql.ExecutionResult;
4+
import graphql.GraphQL;
5+
import graphql.GraphQLError;
6+
import java.util.List;
7+
import java.util.Map;
8+
import lombok.RequiredArgsConstructor;
9+
import org.reactivestreams.Publisher;
10+
11+
@RequiredArgsConstructor
12+
class DecoratedExecutionResult implements ExecutionResult {
13+
14+
private final ExecutionResult result;
15+
16+
static DecoratedExecutionResult decorate(ExecutionResult result) {
17+
return new DecoratedExecutionResult(result);
18+
}
19+
20+
boolean isAsynchronous() {
21+
return result.getData() instanceof Publisher || isDeferred();
22+
}
23+
24+
boolean isDeferred() {
25+
return result.getExtensions() != null && result.getExtensions().containsKey(GraphQL.DEFERRED_RESULTS);
26+
}
27+
28+
@Override
29+
public List<GraphQLError> getErrors() {
30+
return result.getErrors();
31+
}
32+
33+
@Override
34+
public <T> T getData() {
35+
return result.getData();
36+
}
37+
38+
@Override
39+
public boolean isDataPresent() {
40+
return result.isDataPresent();
41+
}
42+
43+
@Override
44+
public Map<Object, Object> getExtensions() {
45+
return result.getExtensions();
46+
}
47+
48+
@Override
49+
public Map<String, Object> toSpecification() {
50+
return result.toSpecification();
51+
}
52+
53+
}
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 java.io.IOException;
4+
import javax.servlet.http.HttpServletRequest;
5+
import javax.servlet.http.HttpServletResponse;
6+
import lombok.RequiredArgsConstructor;
7+
8+
@RequiredArgsConstructor
9+
class ErrorQueryResponseWriter implements QueryResponseWriter {
10+
11+
private final int statusCode;
12+
private final String message;
13+
14+
@Override
15+
public void write(HttpServletRequest request, HttpServletResponse response) throws IOException {
16+
response.sendError(statusCode, message);
17+
}
18+
19+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package graphql.servlet;
2+
3+
import graphql.ExecutionResult;
4+
import graphql.servlet.core.GraphQLObjectMapper;
5+
import java.io.IOException;
6+
import java.io.Writer;
7+
import java.util.concurrent.CountDownLatch;
8+
import java.util.concurrent.atomic.AtomicReference;
9+
import javax.servlet.AsyncContext;
10+
import org.reactivestreams.Subscriber;
11+
import org.reactivestreams.Subscription;
12+
13+
class ExecutionResultSubscriber implements Subscriber<ExecutionResult> {
14+
15+
private final AtomicReference<Subscription> subscriptionRef;
16+
private final AsyncContext asyncContext;
17+
private final GraphQLObjectMapper graphQLObjectMapper;
18+
private final CountDownLatch completedLatch = new CountDownLatch(1);
19+
20+
public ExecutionResultSubscriber(AtomicReference<Subscription> subscriptionRef, AsyncContext asyncContext,
21+
GraphQLObjectMapper graphQLObjectMapper) {
22+
this.subscriptionRef = subscriptionRef;
23+
this.asyncContext = asyncContext;
24+
this.graphQLObjectMapper = graphQLObjectMapper;
25+
}
26+
27+
@Override
28+
public void onSubscribe(Subscription subscription) {
29+
subscriptionRef.set(subscription);
30+
subscriptionRef.get().request(1);
31+
}
32+
33+
@Override
34+
public void onNext(ExecutionResult executionResult) {
35+
try {
36+
Writer writer = asyncContext.getResponse().getWriter();
37+
writer.write("data: ");
38+
graphQLObjectMapper.serializeResultAsJson(writer, executionResult);
39+
writer.write("\n\n");
40+
writer.flush();
41+
subscriptionRef.get().request(1);
42+
} catch (IOException ignored) {
43+
}
44+
}
45+
46+
@Override
47+
public void onError(Throwable t) {
48+
asyncContext.complete();
49+
completedLatch.countDown();
50+
}
51+
52+
@Override
53+
public void onComplete() {
54+
asyncContext.complete();
55+
completedLatch.countDown();
56+
}
57+
58+
public void await() throws InterruptedException {
59+
completedLatch.await();
60+
}
61+
62+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package graphql.servlet;
2+
3+
import graphql.ExecutionResult;
4+
import java.util.List;
5+
import lombok.Getter;
6+
import lombok.RequiredArgsConstructor;
7+
8+
@RequiredArgsConstructor
9+
class GraphQLBatchedQueryResult implements GraphQLQueryResult {
10+
11+
@Getter
12+
private final List<ExecutionResult> results;
13+
14+
@Override
15+
public boolean isBatched() {
16+
return true;
17+
}
18+
19+
@Override
20+
public boolean isAsynchronous() {
21+
return false;
22+
}
23+
24+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package graphql.servlet;
2+
3+
import graphql.ExecutionResult;
4+
import java.util.List;
5+
import lombok.Getter;
6+
import lombok.RequiredArgsConstructor;
7+
8+
@Getter
9+
@RequiredArgsConstructor
10+
class GraphQLErrorQueryResult implements GraphQLQueryResult {
11+
12+
private final int statusCode;
13+
private final String message;
14+
15+
@Override
16+
public boolean isBatched() {
17+
return true;
18+
}
19+
20+
@Override
21+
public boolean isAsynchronous() {
22+
return false;
23+
}
24+
25+
@Override
26+
public boolean isError() {
27+
return true;
28+
}
29+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package graphql.servlet;
2+
3+
import graphql.servlet.context.ContextSetting;
4+
import graphql.servlet.core.GraphQLObjectMapper;
5+
import graphql.servlet.core.internal.GraphQLRequest;
6+
import graphql.servlet.input.GraphQLInvocationInput;
7+
import graphql.servlet.input.GraphQLInvocationInputFactory;
8+
import java.io.IOException;
9+
import java.util.HashMap;
10+
import java.util.List;
11+
import java.util.Map;
12+
import java.util.Optional;
13+
import javax.servlet.http.HttpServletRequest;
14+
import javax.servlet.http.HttpServletResponse;
15+
import lombok.RequiredArgsConstructor;
16+
17+
@RequiredArgsConstructor
18+
class GraphQLInvocationInputParser {
19+
20+
private final GraphQLInvocationInputFactory invocationInputFactory;
21+
private final GraphQLObjectMapper graphQLObjectMapper;
22+
private final ContextSetting contextSetting;
23+
24+
GraphQLInvocationInput getGraphQLInvocationInput(HttpServletRequest request, HttpServletResponse response)
25+
throws IOException {
26+
if (isIntrospectionQuery(request)) {
27+
GraphQLRequest graphqlRequest = GraphQLRequest.createIntrospectionRequest();
28+
return invocationInputFactory.create(graphqlRequest, request, response);
29+
}
30+
31+
String query = request.getParameter("query");
32+
if (!isBatchedQuery(query)) {
33+
Map<String, Object> variables = getVariables(request);
34+
String operationName = request.getParameter("operationName");
35+
GraphQLRequest graphqlRequest = new GraphQLRequest(query, variables, operationName);
36+
return invocationInputFactory.create(graphqlRequest, request, response);
37+
}
38+
39+
List<GraphQLRequest> requests = graphQLObjectMapper.readBatchedGraphQLRequest(query);
40+
return invocationInputFactory.createReadOnly(contextSetting, requests, request, response);
41+
}
42+
43+
private boolean isIntrospectionQuery(HttpServletRequest request) {
44+
String path = Optional.ofNullable(request.getPathInfo()).orElseGet(request::getServletPath).toLowerCase();
45+
return path.contentEquals("/schema.json");
46+
}
47+
48+
private Map<String, Object> getVariables(HttpServletRequest request) {
49+
return Optional.ofNullable(request.getParameter("variables"))
50+
.map(graphQLObjectMapper::deserializeVariables)
51+
.map(HashMap::new)
52+
.orElseGet(HashMap::new);
53+
}
54+
55+
private boolean isBatchedQuery(String query) {
56+
return isArrayStart(query);
57+
}
58+
59+
private boolean isArrayStart(String s) {
60+
return s != null && s.trim().startsWith("[");
61+
}
62+
63+
}

0 commit comments

Comments
 (0)