55import graphql .ExecutionResult ;
66import graphql .introspection .IntrospectionQuery ;
77import graphql .schema .GraphQLFieldDefinition ;
8- import graphql .servlet .internal .GraphQLRequest ;
9- import graphql .servlet .internal .VariableMapper ;
8+ import graphql .servlet .core .GraphQLMBean ;
9+ import graphql .servlet .core .GraphQLObjectMapper ;
10+ import graphql .servlet .core .GraphQLQueryInvoker ;
11+ import graphql .servlet .core .GraphQLServletListener ;
12+ import graphql .servlet .config .GraphQLConfiguration ;
13+ import graphql .servlet .context .ContextSetting ;
14+ import graphql .servlet .input .BatchInputPreProcessResult ;
15+ import graphql .servlet .input .BatchInputPreProcessor ;
16+ import graphql .servlet .input .GraphQLBatchedInvocationInput ;
17+ import graphql .servlet .input .GraphQLSingleInvocationInput ;
18+ import graphql .servlet .input .GraphQLInvocationInputFactory ;
19+ import graphql .servlet .core .internal .GraphQLRequest ;
20+ import graphql .servlet .core .internal .VariableMapper ;
1021import org .reactivestreams .Publisher ;
1122import org .reactivestreams .Subscriber ;
1223import org .reactivestreams .Subscription ;
3041import java .util .ArrayList ;
3142import java .util .Arrays ;
3243import java .util .HashMap ;
44+ import java .util .Iterator ;
3345import java .util .List ;
3446import java .util .Map ;
3547import java .util .Objects ;
4658 */
4759public abstract class AbstractGraphQLHttpServlet extends HttpServlet implements Servlet , GraphQLMBean {
4860
49- public static final Logger log = LoggerFactory .getLogger (AbstractGraphQLHttpServlet .class );
61+ private static final Logger log = LoggerFactory .getLogger (AbstractGraphQLHttpServlet .class );
5062
51- public static final String APPLICATION_JSON_UTF8 = "application/json;charset=UTF-8" ;
52- public static final String APPLICATION_EVENT_STREAM_UTF8 = "text/event-stream;charset=UTF-8" ;
53- public static final String APPLICATION_GRAPHQL = "application/graphql" ;
54- public static final int STATUS_OK = 200 ;
55- public static final int STATUS_BAD_REQUEST = 400 ;
63+ private static final String APPLICATION_JSON_UTF8 = "application/json;charset=UTF-8" ;
64+ private static final String APPLICATION_EVENT_STREAM_UTF8 = "text/event-stream;charset=UTF-8" ;
65+ private static final String APPLICATION_GRAPHQL = "application/graphql" ;
66+ private static final int STATUS_OK = 200 ;
67+ private static final int STATUS_BAD_REQUEST = 400 ;
5668
5769 private static final GraphQLRequest INTROSPECTION_REQUEST = new GraphQLRequest (IntrospectionQuery .INTROSPECTION_QUERY , new HashMap <>(), null );
5870 private static final String [] MULTIPART_KEYS = new String []{"operations" , "graphql" , "query" };
@@ -123,13 +135,17 @@ public void init() {
123135 path = request .getServletPath ();
124136 }
125137 if (path .contentEquals ("/schema.json" )) {
126- query (queryInvoker , graphQLObjectMapper , invocationInputFactory .create (INTROSPECTION_REQUEST , request , response ), response );
138+ query (queryInvoker , graphQLObjectMapper , invocationInputFactory .create (INTROSPECTION_REQUEST , request , response ),
139+ request , response );
127140 } else {
128141 String query = request .getParameter ("query" );
129142 if (query != null ) {
130143
131144 if (isBatchedQuery (query )) {
132- queryBatched (queryInvoker , graphQLObjectMapper , invocationInputFactory .createReadOnly (graphQLObjectMapper .readBatchedGraphQLRequest (query ), request , response ), response );
145+ List <GraphQLRequest > requests = graphQLObjectMapper .readBatchedGraphQLRequest (query );
146+ GraphQLBatchedInvocationInput batchedInvocationInput =
147+ invocationInputFactory .createReadOnly (configuration .getContextSetting (), requests , request , response );
148+ queryBatched (queryInvoker , batchedInvocationInput , request , response , configuration );
133149 } else {
134150 final Map <String , Object > variables = new HashMap <>();
135151 if (request .getParameter ("variables" ) != null ) {
@@ -138,7 +154,9 @@ public void init() {
138154
139155 String operationName = request .getParameter ("operationName" );
140156
141- query (queryInvoker , graphQLObjectMapper , invocationInputFactory .createReadOnly (new GraphQLRequest (query , variables , operationName ), request , response ), response );
157+ query (queryInvoker , graphQLObjectMapper ,
158+ invocationInputFactory .createReadOnly (new GraphQLRequest (query , variables , operationName ), request , response ),
159+ request , response );
142160 }
143161 } else {
144162 response .setStatus (STATUS_BAD_REQUEST );
@@ -155,7 +173,9 @@ public void init() {
155173 try {
156174 if (APPLICATION_GRAPHQL .equals (request .getContentType ())) {
157175 String query = CharStreams .toString (request .getReader ());
158- query (queryInvoker , graphQLObjectMapper , invocationInputFactory .create (new GraphQLRequest (query , null , null ), request , response ), response );
176+ query (queryInvoker , graphQLObjectMapper ,
177+ invocationInputFactory .create (new GraphQLRequest (query , null , null ), request , response ),
178+ request , response );
159179 } else if (request .getContentType () != null && request .getContentType ().startsWith ("multipart/form-data" ) && !request .getParts ().isEmpty ()) {
160180 final Map <String , List <Part >> fileItems = request .getParts ()
161181 .stream ()
@@ -182,10 +202,9 @@ public void init() {
182202 List <GraphQLRequest > graphQLRequests =
183203 graphQLObjectMapper .readBatchedGraphQLRequest (inputStream );
184204 variablesMap .ifPresent (map -> graphQLRequests .forEach (r -> mapMultipartVariables (r , map , fileItems )));
185- GraphQLBatchedInvocationInput invocationInput =
186- invocationInputFactory .create (graphQLRequests , request , response );
187- invocationInput .getContext ().setParts (fileItems );
188- queryBatched (queryInvoker , graphQLObjectMapper , invocationInput , response );
205+ GraphQLBatchedInvocationInput batchedInvocationInput = invocationInputFactory .create (configuration .getContextSetting (),
206+ graphQLRequests , request , response );
207+ queryBatched (queryInvoker , batchedInvocationInput , request , response , configuration );
189208 return ;
190209 } else {
191210 GraphQLRequest graphQLRequest ;
@@ -198,8 +217,7 @@ public void init() {
198217 variablesMap .ifPresent (m -> mapMultipartVariables (graphQLRequest , m , fileItems ));
199218 GraphQLSingleInvocationInput invocationInput =
200219 invocationInputFactory .create (graphQLRequest , request , response );
201- invocationInput .getContext ().setParts (fileItems );
202- query (queryInvoker , graphQLObjectMapper , invocationInput , response );
220+ query (queryInvoker , graphQLObjectMapper , invocationInput , request , response );
203221 return ;
204222 }
205223 }
@@ -211,9 +229,12 @@ public void init() {
211229 InputStream inputStream = asMarkableInputStream (request .getInputStream ());
212230
213231 if (isBatchedQuery (inputStream )) {
214- queryBatched (queryInvoker , graphQLObjectMapper , invocationInputFactory .create (graphQLObjectMapper .readBatchedGraphQLRequest (inputStream ), request , response ), response );
232+ List <GraphQLRequest > requests = graphQLObjectMapper .readBatchedGraphQLRequest (inputStream );
233+ GraphQLBatchedInvocationInput batchedInvocationInput =
234+ invocationInputFactory .create (configuration .getContextSetting (), requests , request , response );
235+ queryBatched (queryInvoker , batchedInvocationInput , request , response , configuration );
215236 } else {
216- query (queryInvoker , graphQLObjectMapper , invocationInputFactory .create (graphQLObjectMapper .readGraphQLRequest (inputStream ), request , response ), response );
237+ query (queryInvoker , graphQLObjectMapper , invocationInputFactory .create (graphQLObjectMapper .readGraphQLRequest (inputStream ), request , response ), request , response );
217238 }
218239 }
219240 } catch (Exception e ) {
@@ -348,18 +369,21 @@ private Optional<Part> getFileItem(Map<String, List<Part>> fileItems, String nam
348369 return Optional .ofNullable (fileItems .get (name )).filter (list -> !list .isEmpty ()).map (list -> list .get (0 ));
349370 }
350371
351- private void query (GraphQLQueryInvoker queryInvoker , GraphQLObjectMapper graphQLObjectMapper , GraphQLSingleInvocationInput invocationInput , HttpServletResponse resp ) throws IOException {
372+ private void query (GraphQLQueryInvoker queryInvoker , GraphQLObjectMapper graphQLObjectMapper , GraphQLSingleInvocationInput invocationInput ,
373+ HttpServletRequest req , HttpServletResponse resp ) throws IOException {
352374 ExecutionResult result = queryInvoker .query (invocationInput );
353375
354376 if (!(result .getData () instanceof Publisher )) {
355377 resp .setContentType (APPLICATION_JSON_UTF8 );
356378 resp .setStatus (STATUS_OK );
357379 resp .getWriter ().write (graphQLObjectMapper .serializeResultAsJson (result ));
358380 } else {
381+ if (req == null ) {
382+ throw new IllegalStateException ("Http servlet request can not be null" );
383+ }
359384 resp .setContentType (APPLICATION_EVENT_STREAM_UTF8 );
360385 resp .setStatus (STATUS_OK );
361386
362- HttpServletRequest req = invocationInput .getContext ().getHttpServletRequest ().orElseThrow (IllegalStateException ::new );
363387 boolean isInAsyncThread = req .isAsyncStarted ();
364388 AsyncContext asyncContext = isInAsyncThread ? req .getAsyncContext () : req .startAsync (req , resp );
365389 asyncContext .setTimeout (configuration .getSubscriptionTimeout ());
@@ -378,8 +402,30 @@ private void query(GraphQLQueryInvoker queryInvoker, GraphQLObjectMapper graphQL
378402 }
379403 }
380404
381- private void queryBatched (GraphQLQueryInvoker queryInvoker , GraphQLObjectMapper graphQLObjectMapper , GraphQLBatchedInvocationInput invocationInput , HttpServletResponse resp ) throws Exception {
382- queryInvoker .query (invocationInput , resp , graphQLObjectMapper );
405+ private void queryBatched (GraphQLQueryInvoker queryInvoker , GraphQLBatchedInvocationInput batchedInvocationInput , HttpServletRequest request ,
406+ HttpServletResponse response , GraphQLConfiguration configuration ) throws IOException {
407+ BatchInputPreProcessor batchInputPreProcessor = configuration .getBatchInputPreProcessor ();
408+ ContextSetting contextSetting = configuration .getContextSetting ();
409+ BatchInputPreProcessResult batchInputPreProcessResult = batchInputPreProcessor .preProcessBatch (batchedInvocationInput , request , response );
410+ if (batchInputPreProcessResult .isExecutable ()) {
411+ List <ExecutionResult > results = queryInvoker .query (batchInputPreProcessResult .getBatchedInvocationInput ().getExecutionInputs (),
412+ contextSetting );
413+ response .setContentType (AbstractGraphQLHttpServlet .APPLICATION_JSON_UTF8 );
414+ response .setStatus (AbstractGraphQLHttpServlet .STATUS_OK );
415+ Writer writer = response .getWriter ();
416+ Iterator <ExecutionResult > executionInputIterator = results .iterator ();
417+ writer .write ("[" );
418+ GraphQLObjectMapper graphQLObjectMapper = configuration .getObjectMapper ();
419+ while (executionInputIterator .hasNext ()) {
420+ writer .write (graphQLObjectMapper .serializeResultAsJson (executionInputIterator .next ()));
421+ if (executionInputIterator .hasNext ()) {
422+ writer .write ("," );
423+ }
424+ }
425+ writer .write ("]" );
426+ } else {
427+ response .sendError (batchInputPreProcessResult .getStatusCode (), batchInputPreProcessResult .getStatusMessage ());
428+ }
383429 }
384430
385431 private <R > List <R > runListeners (Function <? super GraphQLServletListener , R > action ) {
0 commit comments