Skip to content

Commit eca7e6d

Browse files
committed
Reorganize code so GraphQLServlet doesn't contain common code with websocket servlets
1 parent 84a5883 commit eca7e6d

27 files changed

+1246
-991
lines changed

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

Lines changed: 366 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package graphql.servlet;
2+
3+
import graphql.ExecutionInput;
4+
import graphql.execution.ExecutionContext;
5+
import graphql.schema.GraphQLSchema;
6+
import graphql.servlet.internal.GraphQLRequest;
7+
8+
import javax.security.auth.Subject;
9+
import java.util.Collections;
10+
import java.util.List;
11+
import java.util.Optional;
12+
import java.util.stream.Collectors;
13+
14+
/**
15+
* @author Andrew Potter
16+
*/
17+
public class GraphQLBatchedInvocationInput extends GraphQLInvocationInput {
18+
private final List<GraphQLRequest> requests;
19+
20+
public GraphQLBatchedInvocationInput(List<GraphQLRequest> requests, GraphQLSchema schema, GraphQLContext context, Object root) {
21+
super(schema, context, root);
22+
this.requests = Collections.unmodifiableList(requests);
23+
}
24+
25+
public List<ExecutionInput> getExecutionInputs() {
26+
return requests.stream()
27+
.map(this::createExecutionInput)
28+
.collect(Collectors.toList());
29+
}
30+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package graphql.servlet;
2+
3+
import graphql.ExecutionInput;
4+
import graphql.schema.GraphQLSchema;
5+
import graphql.servlet.internal.GraphQLRequest;
6+
7+
import javax.security.auth.Subject;
8+
import java.util.List;
9+
import java.util.Optional;
10+
11+
/**
12+
* @author Andrew Potter
13+
*/
14+
public abstract class GraphQLInvocationInput {
15+
private final GraphQLSchema schema;
16+
private final GraphQLContext context;
17+
private final Object root;
18+
19+
public GraphQLInvocationInput(GraphQLSchema schema, GraphQLContext context, Object root) {
20+
this.schema = schema;
21+
this.context = context;
22+
this.root = root;
23+
}
24+
25+
public GraphQLSchema getSchema() {
26+
return schema;
27+
}
28+
29+
public GraphQLContext getContext() {
30+
return context;
31+
}
32+
33+
public Object getRoot() {
34+
return root;
35+
}
36+
37+
public Optional<Subject> getSubject() {
38+
return context.getSubject();
39+
}
40+
41+
protected ExecutionInput createExecutionInput(GraphQLRequest graphQLRequest) {
42+
return new ExecutionInput(
43+
graphQLRequest.getQuery(),
44+
graphQLRequest.getOperationName(),
45+
context,
46+
root,
47+
graphQLRequest.getVariables()
48+
);
49+
}
50+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package graphql.servlet;
2+
3+
import graphql.schema.GraphQLSchema;
4+
import graphql.servlet.internal.GraphQLRequest;
5+
6+
import javax.servlet.http.HttpServletRequest;
7+
import javax.websocket.server.HandshakeRequest;
8+
import java.util.List;
9+
import java.util.function.Supplier;
10+
11+
/**
12+
* @author Andrew Potter
13+
*/
14+
public class GraphQLInvocationInputFactory {
15+
private final Supplier<GraphQLSchemaProvider> schemaProviderSupplier;
16+
private final Supplier<GraphQLContextBuilder> contextBuilderSupplier;
17+
private final Supplier<GraphQLRootObjectBuilder> rootObjectBuilderSupplier;
18+
19+
protected GraphQLInvocationInputFactory(Supplier<GraphQLSchemaProvider> schemaProviderSupplier, Supplier<GraphQLContextBuilder> contextBuilderSupplier, Supplier<GraphQLRootObjectBuilder> rootObjectBuilderSupplier) {
20+
this.schemaProviderSupplier = schemaProviderSupplier;
21+
this.contextBuilderSupplier = contextBuilderSupplier;
22+
this.rootObjectBuilderSupplier = rootObjectBuilderSupplier;
23+
}
24+
25+
public GraphQLSchemaProvider getSchemaProvider() {
26+
return schemaProviderSupplier.get();
27+
}
28+
29+
public GraphQLSingleInvocationInput create(GraphQLRequest graphQLRequest, HttpServletRequest request) {
30+
return create(graphQLRequest, request, false);
31+
}
32+
33+
public GraphQLBatchedInvocationInput create(List<GraphQLRequest> graphQLRequests, HttpServletRequest request) {
34+
return create(graphQLRequests, request, false);
35+
}
36+
37+
public GraphQLSingleInvocationInput createReadOnly(GraphQLRequest graphQLRequest, HttpServletRequest request) {
38+
return create(graphQLRequest, request, true);
39+
}
40+
41+
public GraphQLBatchedInvocationInput createReadOnly(List<GraphQLRequest> graphQLRequests, HttpServletRequest request) {
42+
return create(graphQLRequests, request, true);
43+
}
44+
45+
public GraphQLSingleInvocationInput create(GraphQLRequest graphQLRequest) {
46+
return new GraphQLSingleInvocationInput(
47+
graphQLRequest,
48+
schemaProviderSupplier.get().getSchema(),
49+
contextBuilderSupplier.get().build(),
50+
rootObjectBuilderSupplier.get().build()
51+
);
52+
}
53+
54+
private GraphQLSingleInvocationInput create(GraphQLRequest graphQLRequest, HttpServletRequest request, boolean readOnly) {
55+
return new GraphQLSingleInvocationInput(
56+
graphQLRequest,
57+
readOnly ? schemaProviderSupplier.get().getReadOnlySchema(request) : schemaProviderSupplier.get().getSchema(request),
58+
contextBuilderSupplier.get().build(request),
59+
rootObjectBuilderSupplier.get().build(request)
60+
);
61+
}
62+
63+
private GraphQLBatchedInvocationInput create(List<GraphQLRequest> graphQLRequests, HttpServletRequest request, boolean readOnly) {
64+
return new GraphQLBatchedInvocationInput(
65+
graphQLRequests,
66+
readOnly ? schemaProviderSupplier.get().getReadOnlySchema(request) : schemaProviderSupplier.get().getSchema(request),
67+
contextBuilderSupplier.get().build(request),
68+
rootObjectBuilderSupplier.get().build(request)
69+
);
70+
}
71+
72+
public GraphQLSingleInvocationInput create(GraphQLRequest graphQLRequest, HandshakeRequest request) {
73+
return new GraphQLSingleInvocationInput(
74+
graphQLRequest,
75+
schemaProviderSupplier.get().getSchema(request),
76+
contextBuilderSupplier.get().build(request),
77+
rootObjectBuilderSupplier.get().build(request)
78+
);
79+
}
80+
81+
public GraphQLBatchedInvocationInput create(List<GraphQLRequest> graphQLRequest, HandshakeRequest request) {
82+
return new GraphQLBatchedInvocationInput(
83+
graphQLRequest,
84+
schemaProviderSupplier.get().getSchema(request),
85+
contextBuilderSupplier.get().build(request),
86+
rootObjectBuilderSupplier.get().build(request)
87+
);
88+
}
89+
90+
public static Builder newBuilder(GraphQLSchema schema) {
91+
return new Builder(new DefaultGraphQLSchemaProvider(schema));
92+
}
93+
94+
public static Builder newBuilder(GraphQLSchemaProvider schemaProvider) {
95+
return new Builder(schemaProvider);
96+
}
97+
98+
public static Builder newBuilder(Supplier<GraphQLSchemaProvider> schemaProviderSupplier) {
99+
return new Builder(schemaProviderSupplier);
100+
}
101+
102+
public static class Builder {
103+
private final Supplier<GraphQLSchemaProvider> schemaProviderSupplier;
104+
private Supplier<GraphQLContextBuilder> contextBuilderSupplier = DefaultGraphQLContextBuilder::new;
105+
private Supplier<GraphQLRootObjectBuilder> rootObjectBuilderSupplier = DefaultGraphQLRootObjectBuilder::new;
106+
107+
public Builder(GraphQLSchemaProvider schemaProvider) {
108+
this(() -> schemaProvider);
109+
}
110+
111+
public Builder(Supplier<GraphQLSchemaProvider> schemaProviderSupplier) {
112+
this.schemaProviderSupplier = schemaProviderSupplier;
113+
}
114+
115+
public Builder withGraphQLContextBuilder(GraphQLContextBuilder contextBuilder) {
116+
return withGraphQLContextBuilder(() -> contextBuilder);
117+
}
118+
119+
public Builder withGraphQLContextBuilder(Supplier<GraphQLContextBuilder> contextBuilderSupplier) {
120+
this.contextBuilderSupplier = contextBuilderSupplier;
121+
return this;
122+
}
123+
124+
public Builder withGraphQLRootObjectBuilder(GraphQLRootObjectBuilder rootObjectBuilder) {
125+
return withGraphQLRootObjectBuilder(() -> rootObjectBuilder);
126+
}
127+
128+
public Builder withGraphQLRootObjectBuilder(Supplier<GraphQLRootObjectBuilder> rootObjectBuilderSupplier) {
129+
this.rootObjectBuilderSupplier = rootObjectBuilderSupplier;
130+
return this;
131+
}
132+
133+
public GraphQLInvocationInputFactory build() {
134+
return new GraphQLInvocationInputFactory(schemaProviderSupplier, contextBuilderSupplier, rootObjectBuilderSupplier);
135+
}
136+
}
137+
}
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
package graphql.servlet;
2+
3+
import com.fasterxml.jackson.core.JsonProcessingException;
4+
import com.fasterxml.jackson.databind.InjectableValues;
5+
import com.fasterxml.jackson.databind.MappingIterator;
6+
import com.fasterxml.jackson.databind.ObjectMapper;
7+
import com.fasterxml.jackson.databind.ObjectReader;
8+
import com.fasterxml.jackson.databind.SerializationFeature;
9+
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
10+
import graphql.ExecutionResult;
11+
import graphql.servlet.internal.GraphQLRequest;
12+
import graphql.servlet.internal.VariablesDeserializer;
13+
14+
import java.io.IOException;
15+
import java.io.InputStream;
16+
import java.util.ArrayList;
17+
import java.util.LinkedHashMap;
18+
import java.util.List;
19+
import java.util.Map;
20+
import java.util.function.Supplier;
21+
22+
/**
23+
* @author Andrew Potter
24+
*/
25+
public class GraphQLObjectMapper {
26+
private final Supplier<ObjectMapperConfigurer> objectMapperConfigurerSupplier;
27+
private final Supplier<GraphQLErrorHandler> graphQLErrorHandlerSupplier;
28+
29+
private volatile ObjectMapper mapper;
30+
31+
protected GraphQLObjectMapper(Supplier<ObjectMapperConfigurer> objectMapperConfigurerSupplier, Supplier<GraphQLErrorHandler> graphQLErrorHandlerSupplier) {
32+
this.objectMapperConfigurerSupplier = objectMapperConfigurerSupplier;
33+
this.graphQLErrorHandlerSupplier = graphQLErrorHandlerSupplier;
34+
}
35+
36+
// Double-check idiom for lazy initialization of instance fields.
37+
public ObjectMapper getJacksonMapper() {
38+
ObjectMapper result = mapper;
39+
if (result == null) { // First check (no locking)
40+
synchronized(this) {
41+
result = mapper;
42+
if (result == null) // Second check (with locking)
43+
mapper = result = createObjectMapper();
44+
}
45+
}
46+
47+
return result;
48+
}
49+
50+
private ObjectMapper createObjectMapper() {
51+
ObjectMapper mapper = new ObjectMapper().disable(SerializationFeature.FAIL_ON_EMPTY_BEANS).registerModule(new Jdk8Module());
52+
objectMapperConfigurerSupplier.get().configure(mapper);
53+
54+
return mapper;
55+
}
56+
57+
/**
58+
* Creates an {@link ObjectReader} for deserializing {@link GraphQLRequest}
59+
*/
60+
public ObjectReader getGraphQLRequestMapper() {
61+
// Add object mapper to injection so VariablesDeserializer can access it...
62+
InjectableValues.Std injectableValues = new InjectableValues.Std();
63+
injectableValues.addValue(ObjectMapper.class, getJacksonMapper());
64+
65+
return getJacksonMapper().reader(injectableValues).forType(GraphQLRequest.class);
66+
}
67+
68+
public GraphQLRequest readGraphQLRequest(InputStream inputStream) throws IOException {
69+
return getGraphQLRequestMapper().readValue(inputStream);
70+
}
71+
72+
public List<GraphQLRequest> readBatchedGraphQLRequest(InputStream inputStream) throws IOException {
73+
MappingIterator<GraphQLRequest> iterator = getGraphQLRequestMapper().readValues(inputStream);
74+
List<GraphQLRequest> requests = new ArrayList<>();
75+
76+
while (iterator.hasNext()) {
77+
requests.add(iterator.next());
78+
}
79+
80+
return requests;
81+
}
82+
83+
public List<GraphQLRequest> readBatchedGraphQLRequest(String query) throws IOException {
84+
MappingIterator<GraphQLRequest> iterator = getGraphQLRequestMapper().readValues(query);
85+
List<GraphQLRequest> requests = new ArrayList<>();
86+
87+
while (iterator.hasNext()) {
88+
requests.add(iterator.next());
89+
}
90+
91+
return requests;
92+
}
93+
94+
public String serializeResultAsJson(ExecutionResult executionResult) {
95+
try {
96+
return getJacksonMapper().writeValueAsString(createResultFromExecutionResult(executionResult));
97+
} catch (JsonProcessingException e) {
98+
throw new RuntimeException(e);
99+
}
100+
}
101+
102+
public Map<String, Object> createResultFromExecutionResult(ExecutionResult executionResult) {
103+
104+
GraphQLErrorHandler errorHandler = graphQLErrorHandlerSupplier.get();
105+
106+
final Map<String, Object> result = new LinkedHashMap<>();
107+
result.put("data", executionResult.getData());
108+
109+
if (errorHandler.errorsPresent(executionResult.getErrors())) {
110+
result.put("errors", errorHandler.processErrors(executionResult.getErrors()));
111+
}
112+
113+
if(executionResult.getExtensions() != null){
114+
result.put("extensions", executionResult.getExtensions());
115+
}
116+
117+
return result;
118+
}
119+
120+
public Map<String, Object> deserializeVariables(String variables) {
121+
try {
122+
return VariablesDeserializer.deserializeVariablesObject(getJacksonMapper().readValue(variables, Object.class), getJacksonMapper());
123+
} catch (IOException e) {
124+
throw new RuntimeException(e);
125+
}
126+
}
127+
128+
public static Builder newBuilder() {
129+
return new Builder();
130+
}
131+
132+
public static class Builder {
133+
private Supplier<ObjectMapperConfigurer> objectMapperConfigurer = DefaultObjectMapperConfigurer::new;
134+
private Supplier<GraphQLErrorHandler> graphQLErrorHandler = DefaultGraphQLErrorHandler::new;
135+
136+
public Builder withObjectMapperConfigurer(ObjectMapperConfigurer objectMapperConfigurer) {
137+
return withObjectMapperConfigurer(() -> objectMapperConfigurer);
138+
}
139+
140+
public Builder withObjectMapperConfigurer(Supplier<ObjectMapperConfigurer> objectMapperConfigurer) {
141+
this.objectMapperConfigurer = objectMapperConfigurer;
142+
return this;
143+
}
144+
145+
public Builder withGraphQLErrorHandler(GraphQLErrorHandler graphQLErrorHandler) {
146+
return withGraphQLErrorHandler(() -> graphQLErrorHandler);
147+
}
148+
149+
public Builder withGraphQLErrorHandler(Supplier<GraphQLErrorHandler> graphQLErrorHandler) {
150+
this.graphQLErrorHandler = graphQLErrorHandler;
151+
return this;
152+
}
153+
154+
public GraphQLObjectMapper build() {
155+
return new GraphQLObjectMapper(objectMapperConfigurer, graphQLErrorHandler);
156+
}
157+
}
158+
}

0 commit comments

Comments
 (0)