1111import graphql .execution .preparsed .NoOpPreparsedDocumentProvider ;
1212import graphql .execution .preparsed .PreparsedDocumentProvider ;
1313import graphql .schema .GraphQLSchema ;
14+ import graphql .servlet .core .AbstractGraphQLHttpServlet ;
15+ import graphql .servlet .input .BatchInputPreProcessResult ;
16+ import graphql .servlet .input .BatchInputPreProcessor ;
17+ import graphql .servlet .input .ContextSetting ;
18+ import graphql .servlet .input .GraphQLBatchedInvocationInput ;
19+ import graphql .servlet .input .GraphQLSingleInvocationInput ;
20+ import graphql .servlet .input .NoOpBatchInputPreProcessor ;
1421
1522import javax .security .auth .Subject ;
23+ import javax .servlet .http .HttpServletRequest ;
1624import javax .servlet .http .HttpServletResponse ;
25+ import java .io .IOException ;
1726import java .io .Writer ;
1827import java .security .AccessController ;
1928import java .security .PrivilegedAction ;
20- import java .util .ArrayList ;
29+ import java .util .Iterator ;
2130import java .util .List ;
31+ import java .util .concurrent .CompletableFuture ;
2232import java .util .function .Supplier ;
33+ import java .util .stream .Collectors ;
2334
2435/**
2536 * @author Andrew Potter
@@ -29,52 +40,76 @@ public class GraphQLQueryInvoker {
2940 private final Supplier <ExecutionStrategyProvider > getExecutionStrategyProvider ;
3041 private final Supplier <Instrumentation > getInstrumentation ;
3142 private final Supplier <PreparsedDocumentProvider > getPreparsedDocumentProvider ;
32- private final Supplier <DataLoaderDispatcherInstrumentationOptions > dataLoaderDispatcherInstrumentationOptionsSupplier ;
33- private final BatchExecutionHandler batchExecutionHandler ;
43+ private final Supplier <BatchInputPreProcessor > batchInputPreProcessor ;
44+ private final Supplier < DataLoaderDispatcherInstrumentationOptions > optionsSupplier ;
3445
35- protected GraphQLQueryInvoker (Supplier <ExecutionStrategyProvider > getExecutionStrategyProvider , Supplier <Instrumentation > getInstrumentation , Supplier <PreparsedDocumentProvider > getPreparsedDocumentProvider , Supplier <DataLoaderDispatcherInstrumentationOptions > optionsSupplier , BatchExecutionHandler batchExecutionHandler ) {
46+ protected GraphQLQueryInvoker (Supplier <ExecutionStrategyProvider > getExecutionStrategyProvider , Supplier <Instrumentation > getInstrumentation ,
47+ Supplier <PreparsedDocumentProvider > getPreparsedDocumentProvider ,
48+ Supplier <BatchInputPreProcessor > batchInputPreProcessor ,
49+ Supplier <DataLoaderDispatcherInstrumentationOptions > optionsSupplier ) {
3650 this .getExecutionStrategyProvider = getExecutionStrategyProvider ;
3751 this .getInstrumentation = getInstrumentation ;
3852 this .getPreparsedDocumentProvider = getPreparsedDocumentProvider ;
39- this .dataLoaderDispatcherInstrumentationOptionsSupplier = optionsSupplier ;
40- this .batchExecutionHandler = batchExecutionHandler ;
53+ this .batchInputPreProcessor = batchInputPreProcessor ;
54+ this .optionsSupplier = optionsSupplier ;
4155 }
4256
4357 public ExecutionResult query (GraphQLSingleInvocationInput singleInvocationInput ) {
44- return query (singleInvocationInput , singleInvocationInput . getExecutionInput () );
58+ return queryAsync (singleInvocationInput , getInstrumentation ). join ( );
4559 }
4660
47- public void query ( GraphQLBatchedInvocationInput batchedInvocationInput , HttpServletResponse response , GraphQLObjectMapper graphQLObjectMapper ) {
48- batchExecutionHandler . handleBatch ( batchedInvocationInput , response , graphQLObjectMapper , this :: query );
61+ private CompletableFuture < ExecutionResult > queryAsync ( GraphQLSingleInvocationInput singleInvocationInput , Supplier < Instrumentation > configuredInstrumentation ) {
62+ return query ( singleInvocationInput , configuredInstrumentation , singleInvocationInput . getExecutionInput () );
4963 }
5064
51- private GraphQL newGraphQL (GraphQLSchema schema , Object context ) {
65+ public void query (GraphQLBatchedInvocationInput batchedInvocationInput , ContextSetting contextSetting , HttpServletRequest request , HttpServletResponse response ,
66+ GraphQLObjectMapper graphQLObjectMapper ) {
67+ BatchInputPreProcessResult processedInput = batchInputPreProcessor .get ().preProcessBatch (batchedInvocationInput , request , response );
68+ if (processedInput .isExecutable ()) {
69+ response .setContentType (AbstractGraphQLHttpServlet .APPLICATION_JSON_UTF8 );
70+ response .setStatus (AbstractGraphQLHttpServlet .STATUS_OK );
71+ List <ExecutionInput > executionIds = batchedInvocationInput .getExecutionInputs ().stream ()
72+ .map (GraphQLSingleInvocationInput ::getExecutionInput )
73+ .collect (Collectors .toList ());
74+ Supplier <Instrumentation > configuredInstrumentation = contextSetting .configureInstrumentationForContext (getInstrumentation , executionIds ,
75+ optionsSupplier .get ());
76+ Iterator <CompletableFuture <ExecutionResult >> resultIter = processedInput .getBatchedInvocationInput ().getExecutionInputs ().stream ()
77+ .map (input -> this .queryAsync (input , configuredInstrumentation ))
78+ //We want eager eval
79+ .collect (Collectors .toList ())
80+ .iterator ();
81+
82+ try {
83+ Writer writer = response .getWriter ();
84+ writer .write ("[" );
85+ while (resultIter .hasNext ()) {
86+ ExecutionResult current = resultIter .next ().join ();
87+ writer .write (graphQLObjectMapper .serializeResultAsJson (current ));
88+ if (resultIter .hasNext ()) {
89+ writer .write ("," );
90+ }
91+ }
92+ writer .write ("]" );
93+ } catch (IOException ex ) {
94+ throw new RuntimeException (ex );
95+ }
96+ }
97+ //TODO should we check if the batch pre processor set the status in an else? if not what would we set?
98+ }
99+
100+ private GraphQL newGraphQL (GraphQLSchema schema , Supplier <Instrumentation > configuredInstrumentation ) {
52101 ExecutionStrategyProvider executionStrategyProvider = getExecutionStrategyProvider .get ();
53- return GraphQL .newGraphQL (schema )
102+ GraphQL . Builder builder = GraphQL .newGraphQL (schema )
54103 .queryExecutionStrategy (executionStrategyProvider .getQueryExecutionStrategy ())
55104 .mutationExecutionStrategy (executionStrategyProvider .getMutationExecutionStrategy ())
56105 .subscriptionExecutionStrategy (executionStrategyProvider .getSubscriptionExecutionStrategy ())
57- .instrumentation (getInstrumentation (context ))
58- .preparsedDocumentProvider (getPreparsedDocumentProvider .get ())
59- .build ();
60- }
61-
62- protected Instrumentation getInstrumentation (Object context ) {
63- if (context instanceof GraphQLContext ) {
64- return ((GraphQLContext ) context ).getDataLoaderRegistry ()
65- .map (registry -> {
66- Instrumentation instrumentation = getInstrumentation .get ();
67- if (!containsDispatchInstrumentation (instrumentation )) {
68- List <Instrumentation > instrumentations = new ArrayList <>();
69- instrumentations .add (instrumentation );
70- instrumentations .add (new DataLoaderDispatcherInstrumentation (dataLoaderDispatcherInstrumentationOptionsSupplier .get ()));
71- instrumentation = new ChainedInstrumentation (instrumentations );
72- }
73- return instrumentation ;
74- })
75- .orElse (getInstrumentation .get ());
76- }
77- return getInstrumentation .get ();
106+ .preparsedDocumentProvider (getPreparsedDocumentProvider .get ());
107+ Instrumentation instrumentation = configuredInstrumentation .get ();
108+ builder .instrumentation (instrumentation );
109+ if (containsDispatchInstrumentation (instrumentation )) {
110+ builder .doNotAddDefaultInstrumentations ();
111+ }
112+ return builder .build ();
78113 }
79114
80115 private boolean containsDispatchInstrumentation (Instrumentation instrumentation ) {
@@ -84,22 +119,22 @@ private boolean containsDispatchInstrumentation(Instrumentation instrumentation)
84119 return instrumentation instanceof DataLoaderDispatcherInstrumentation ;
85120 }
86121
87- private ExecutionResult query (GraphQLInvocationInput invocationInput , ExecutionInput executionInput ) {
122+ private CompletableFuture < ExecutionResult > query (GraphQLSingleInvocationInput invocationInput , Supplier < Instrumentation > configuredInstrumentation , ExecutionInput executionInput ) {
88123 if (Subject .getSubject (AccessController .getContext ()) == null && invocationInput .getSubject ().isPresent ()) {
89- return Subject .doAs (invocationInput .getSubject ().get (), (PrivilegedAction <ExecutionResult >) () -> {
124+ return Subject .doAs (invocationInput .getSubject ().get (), (PrivilegedAction <CompletableFuture < ExecutionResult > >) () -> {
90125 try {
91- return query (invocationInput .getSchema (), executionInput );
126+ return query (invocationInput .getSchema (), executionInput , configuredInstrumentation );
92127 } catch (Exception e ) {
93128 throw new RuntimeException (e );
94129 }
95130 });
96131 }
97132
98- return query (invocationInput .getSchema (), executionInput );
133+ return query (invocationInput .getSchema (), executionInput , configuredInstrumentation );
99134 }
100135
101- private ExecutionResult query (GraphQLSchema schema , ExecutionInput executionInput ) {
102- return newGraphQL (schema , executionInput . getContext ()). execute (executionInput );
136+ private CompletableFuture < ExecutionResult > query (GraphQLSchema schema , ExecutionInput executionInput , Supplier < Instrumentation > configuredInstrumentation ) {
137+ return newGraphQL (schema , configuredInstrumentation ). executeAsync (executionInput );
103138 }
104139
105140 public static Builder newBuilder () {
@@ -110,8 +145,9 @@ public static class Builder {
110145 private Supplier <ExecutionStrategyProvider > getExecutionStrategyProvider = DefaultExecutionStrategyProvider ::new ;
111146 private Supplier <Instrumentation > getInstrumentation = () -> SimpleInstrumentation .INSTANCE ;
112147 private Supplier <PreparsedDocumentProvider > getPreparsedDocumentProvider = () -> NoOpPreparsedDocumentProvider .INSTANCE ;
148+ private Supplier <BatchInputPreProcessor > batchInputPreProcessor = () -> new NoOpBatchInputPreProcessor ();
113149 private Supplier <DataLoaderDispatcherInstrumentationOptions > dataLoaderDispatcherInstrumentationOptionsSupplier = DataLoaderDispatcherInstrumentationOptions ::newOptions ;
114- private BatchExecutionHandler batchExecutionHandler = new DefaultBatchExecutionHandler ();
150+
115151
116152 public Builder withExecutionStrategyProvider (ExecutionStrategyProvider provider ) {
117153 return withExecutionStrategyProvider (() -> provider );
@@ -143,9 +179,16 @@ public Builder with(List<Instrumentation> instrumentations) {
143179 return this ;
144180 }
145181
146- public Builder withBatchExeuctionHandler (BatchExecutionHandler batchExeuctionHandler ) {
147- if (batchExeuctionHandler != null ) {
148- this .batchExecutionHandler = batchExeuctionHandler ;
182+ public Builder withBatchInputPreProcessor (BatchInputPreProcessor batchInputPreProcessor ) {
183+ if (batchInputPreProcessor != null ) {
184+ this .batchInputPreProcessor = () -> batchInputPreProcessor ;
185+ }
186+ return this ;
187+ }
188+
189+ public Builder withBatchInputPreProcessor (Supplier <BatchInputPreProcessor > batchInputPreProcessor ) {
190+ if (batchInputPreProcessor != null ) {
191+ this .batchInputPreProcessor = batchInputPreProcessor ;
149192 }
150193 return this ;
151194 }
@@ -169,7 +212,8 @@ public Builder withDataLoaderDispatcherInstrumentationOptions(Supplier<DataLoade
169212 }
170213
171214 public GraphQLQueryInvoker build () {
172- return new GraphQLQueryInvoker (getExecutionStrategyProvider , getInstrumentation , getPreparsedDocumentProvider , dataLoaderDispatcherInstrumentationOptionsSupplier , batchExecutionHandler );
215+ return new GraphQLQueryInvoker (getExecutionStrategyProvider , getInstrumentation , getPreparsedDocumentProvider , batchInputPreProcessor ,
216+ dataLoaderDispatcherInstrumentationOptionsSupplier );
173217 }
174218 }
175219}
0 commit comments