You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2020/03/27 15:23:41 UTC
[sling-whiteboard] branch master updated (e09d8fa -> 1561999)
This is an automated email from the ASF dual-hosted git repository.
bdelacretaz pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git.
from e09d8fa Content-based tests setup, ready to plug in the actual GraphQL engine
new 639cc83 Add graphql-java
new e09c3df GraphQL query engine added, minimal 'current resource path' query works
new 1561999 README
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
graphql-scripting/README.md | 14 +++-
graphql-scripting/pom.xml | 16 +++--
.../gql/internal/GraphQLResourceQuery.java | 81 ++++++++++++++++++++++
.../gql/internal/GraphQLScriptEngine.java | 19 ++++-
.../gql/internal/GraphQLResourceQueryTest.java | 48 +++++++++++++
.../sling/scripting/graphql/it/BasicContentIT.java | 10 +--
.../graphql/it/GraphQLScriptingTestSupport.java | 41 ++++++++++-
.../initial-content/apps/graphql/test/one/json.gql | 19 ++++-
8 files changed, 233 insertions(+), 15 deletions(-)
create mode 100644 graphql-scripting/src/main/java/org/apache/sling/scripting/gql/internal/GraphQLResourceQuery.java
create mode 100644 graphql-scripting/src/test/java/org/apache/sling/scripting/gql/internal/GraphQLResourceQueryTest.java
[sling-whiteboard] 02/03: GraphQL query engine added,
minimal 'current resource path' query works
Posted by bd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
bdelacretaz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git
commit e09c3df3b2828b5c8e9021abf7f1e15904c86033
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Fri Mar 27 16:18:30 2020 +0100
GraphQL query engine added, minimal 'current resource path' query works
---
graphql-scripting/pom.xml | 6 ++
.../gql/internal/GraphQLResourceQuery.java | 81 ++++++++++++++++++++++
.../gql/internal/GraphQLScriptEngine.java | 19 ++++-
.../gql/internal/GraphQLResourceQueryTest.java | 48 +++++++++++++
.../sling/scripting/graphql/it/BasicContentIT.java | 10 +--
.../graphql/it/GraphQLScriptingTestSupport.java | 2 +-
.../initial-content/apps/graphql/test/one/json.gql | 19 ++++-
7 files changed, 176 insertions(+), 9 deletions(-)
diff --git a/graphql-scripting/pom.xml b/graphql-scripting/pom.xml
index 7852c61..c6ef7cb 100644
--- a/graphql-scripting/pom.xml
+++ b/graphql-scripting/pom.xml
@@ -180,6 +180,12 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.10.19</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.servlet-helpers</artifactId>
<version>1.3.0</version>
diff --git a/graphql-scripting/src/main/java/org/apache/sling/scripting/gql/internal/GraphQLResourceQuery.java b/graphql-scripting/src/main/java/org/apache/sling/scripting/gql/internal/GraphQLResourceQuery.java
new file mode 100644
index 0000000..37217c3
--- /dev/null
+++ b/graphql-scripting/src/main/java/org/apache/sling/scripting/gql/internal/GraphQLResourceQuery.java
@@ -0,0 +1,81 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sling.scripting.gql.internal;
+
+import java.util.Date;
+
+import org.apache.sling.api.resource.Resource;
+
+import graphql.ExecutionResult;
+import graphql.GraphQL;
+import graphql.schema.DataFetcher;
+import graphql.schema.DataFetchingEnvironment;
+import graphql.schema.GraphQLSchema;
+import graphql.schema.idl.RuntimeWiring;
+import graphql.schema.idl.SchemaGenerator;
+import graphql.schema.idl.SchemaParser;
+import graphql.schema.idl.TypeDefinitionRegistry;
+import graphql.schema.idl.TypeRuntimeWiring;
+
+/** Run a GraphQL query in the context of a Sling Resource */
+class GraphQLResourceQuery {
+
+ static class EchoDataFetcher implements DataFetcher<Object> {
+ private final Object data;
+
+ EchoDataFetcher(Object data) {
+ this.data = data;
+ }
+ @Override
+ public Object get(DataFetchingEnvironment environment) throws Exception {
+ return data;
+ }
+ }
+
+ ExecutionResult executeQuery(Resource r, String query) {
+ final String schemaDef =
+ "type Query { currentResource : SlingResource }\n"
+ + "type SlingResource { path: String }\n"
+ ;
+
+ final GraphQLSchema schema = buildSchema(schemaDef, r);
+ final GraphQL graphQL = GraphQL.newGraphQL(schema).build();
+ final ExecutionResult result = graphQL.execute(query);
+ return result;
+ }
+
+ private GraphQLSchema buildSchema(String sdl, Resource r) {
+ TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl);
+ RuntimeWiring runtimeWiring = buildWiring(r);
+ SchemaGenerator schemaGenerator = new SchemaGenerator();
+ return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring);
+ }
+
+ private RuntimeWiring buildWiring(Resource r) {
+ // TODO data should pass via the DataFetchingEnvironment...
+ final String path = r == null ? "NO_PATH" : r.getPath();
+ return RuntimeWiring.newRuntimeWiring()
+ .type(TypeRuntimeWiring.newTypeWiring("Query").dataFetcher("currentResource", new EchoDataFetcher("DummyCurrentResourceResult")).build())
+ .type(TypeRuntimeWiring.newTypeWiring("SlingResource").dataFetcher("path", new EchoDataFetcher(path)).build())
+ .build()
+ ;
+ }
+}
diff --git a/graphql-scripting/src/main/java/org/apache/sling/scripting/gql/internal/GraphQLScriptEngine.java b/graphql-scripting/src/main/java/org/apache/sling/scripting/gql/internal/GraphQLScriptEngine.java
index 812d002..4d4c43b 100644
--- a/graphql-scripting/src/main/java/org/apache/sling/scripting/gql/internal/GraphQLScriptEngine.java
+++ b/graphql-scripting/src/main/java/org/apache/sling/scripting/gql/internal/GraphQLScriptEngine.java
@@ -23,7 +23,6 @@ package org.apache.sling.scripting.gql.internal;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
-import java.util.Date;
import javax.script.AbstractScriptEngine;
import javax.script.Bindings;
@@ -32,6 +31,10 @@ import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
import org.apache.commons.io.IOUtils;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.scripting.SlingBindings;
+
+import graphql.ExecutionResult;
public class GraphQLScriptEngine extends AbstractScriptEngine {
@@ -49,8 +52,18 @@ public class GraphQLScriptEngine extends AbstractScriptEngine {
@Override
public Object eval(Reader reader, ScriptContext context) throws ScriptException {
try {
- // TODO no execution so far...
- IOUtils.copy(reader, context.getWriter());
+ final GraphQLResourceQuery q = new GraphQLResourceQuery();
+
+ final Resource resource = (Resource) context.getBindings(ScriptContext.ENGINE_SCOPE).get(SlingBindings.RESOURCE);
+ final ExecutionResult result = q.executeQuery(resource, IOUtils.toString(reader));
+ if(!result.getErrors().isEmpty()) {
+ throw new ScriptException(("GraphQL query failed:" + result.getErrors()));
+ }
+ final Object data = result.getData();
+ if(data == null) {
+ throw new ScriptException("No data");
+ }
+ IOUtils.copy(new StringReader(data.toString()), context.getWriter());
} catch(IOException e) {
throw new ScriptException(e);
}
diff --git a/graphql-scripting/src/test/java/org/apache/sling/scripting/gql/internal/GraphQLResourceQueryTest.java b/graphql-scripting/src/test/java/org/apache/sling/scripting/gql/internal/GraphQLResourceQueryTest.java
new file mode 100644
index 0000000..9218b37
--- /dev/null
+++ b/graphql-scripting/src/test/java/org/apache/sling/scripting/gql/internal/GraphQLResourceQueryTest.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.scripting.gql.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.util.UUID;
+
+import org.apache.sling.api.resource.Resource;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import graphql.ExecutionResult;
+
+public class GraphQLResourceQueryTest {
+ @Test
+ public void basicTest() throws Exception {
+ final String path = "/some/path/" + UUID.randomUUID();
+ final Resource r = Mockito.mock(Resource.class);
+ Mockito.when(r.getPath()).thenReturn(path);
+
+ final GraphQLResourceQuery q = new GraphQLResourceQuery();
+ final ExecutionResult result = q.executeQuery(r, "{ currentResource { path } }");
+
+ if(!result.getErrors().isEmpty()) {
+ fail("Errors:" + result.getErrors());
+ }
+ final String expected = "{currentResource={path=" + path + "}}";
+ assertEquals(expected, result.getData().toString());
+ }
+}
diff --git a/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/BasicContentIT.java b/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/BasicContentIT.java
index b2ca6f1..750dd67 100644
--- a/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/BasicContentIT.java
+++ b/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/BasicContentIT.java
@@ -30,7 +30,8 @@ import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerClass;
import org.ops4j.pax.exam.util.Filter;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.ops4j.pax.exam.cm.ConfigurationAdminOptions.factoryConfiguration;
@RunWith(PaxExam.class)
@@ -53,9 +54,10 @@ public class BasicContentIT extends GraphQLScriptingTestSupport {
@Test
public void testJsonContent() throws Exception {
- final String content = getContent("/graphql/one.json");
- assertTrue("Expecting the right content:" + content,
- content.contains("One day this will be a GraphQL query"));
+ final String expected = "{currentResource={path=/content/graphql/one}}";
+ final String actual = getContent("/graphql/one.json");
+ assertNotNull(actual);
+ assertEquals(expected, actual.trim());
}
}
diff --git a/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/GraphQLScriptingTestSupport.java b/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/GraphQLScriptingTestSupport.java
index 9ae877b..6f22cc9 100644
--- a/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/GraphQLScriptingTestSupport.java
+++ b/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/GraphQLScriptingTestSupport.java
@@ -148,7 +148,7 @@ public abstract class GraphQLScriptingTestSupport extends TestSupport {
if (expectedStatus > 0) {
assertEquals("Expected status " + expectedStatus + " for " + method
- + " at " + path, expectedStatus, response.getStatus());
+ + " at " + path + " - content=" + response.getOutputAsString(), expectedStatus, response.getStatus());
}
return response;
diff --git a/graphql-scripting/src/test/resources/initial-content/apps/graphql/test/one/json.gql b/graphql-scripting/src/test/resources/initial-content/apps/graphql/test/one/json.gql
index 32539ce..16bd6e4 100644
--- a/graphql-scripting/src/test/resources/initial-content/apps/graphql/test/one/json.gql
+++ b/graphql-scripting/src/test/resources/initial-content/apps/graphql/test/one/json.gql
@@ -1 +1,18 @@
-One day this will be a GraphQL query
\ No newline at end of file
+# * Licensed to the Apache Software Foundation (ASF) under one
+# * or more contributor license agreements. See the NOTICE file
+# * distributed with this work for additional information
+# * regarding copyright ownership. The ASF licenses this file
+# * to you under the Apache License, Version 2.0 (the
+# * "License"); you may not use this file except in compliance
+# * with the License. You may obtain a copy of the License at
+# *
+# * http://www.apache.org/licenses/LICENSE-2.0
+# *
+# * Unless required by applicable law or agreed to in writing,
+# * software distributed under the License is distributed on an
+# * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# * KIND, either express or implied. See the License for the
+# * specific language governing permissions and limitations
+# * under the License.
+
+{ currentResource { path } }
\ No newline at end of file
[sling-whiteboard] 03/03: README
Posted by bd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
bdelacretaz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git
commit 1561999c7124557f726000f3d86011e85b0d409a
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Fri Mar 27 16:23:28 2020 +0100
README
---
graphql-scripting/README.md | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/graphql-scripting/README.md b/graphql-scripting/README.md
index 47496e2..b6d4600 100644
--- a/graphql-scripting/README.md
+++ b/graphql-scripting/README.md
@@ -1,9 +1,19 @@
-graphql-scripting
+Apache Sling GraphQL Scripting Engine
----
This is an experiment to run GraphQL queries server-side in Sling.
-It implements two Sling Scripting Engines, one for a `.gql` extension which
+----
+
+**Status**: at commit `e09c3df3`, the GraphQL engine is functional,
+a request to a Resource `/foo` mapped to a .gql script containing
+`{ currentResource { path } }` returns `{currentResource={path=/foo}}`.
+This demonstrates the server-side execution of GraphQL queries,
+in the context of the current Resource.
+
+----
+
+This module implements two Sling Scripting Engines, one for a `.gql` extension which
provides the actual GraphQL queries, and one for a `.gqls` extension which
provides GraphQL schema fragments.
[sling-whiteboard] 01/03: Add graphql-java
Posted by bd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
bdelacretaz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git
commit 639cc8359213e70dae710764369d2ca27cce9033
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Fri Mar 27 14:39:29 2020 +0100
Add graphql-java
---
graphql-scripting/pom.xml | 10 +++---
.../graphql/it/GraphQLScriptingTestSupport.java | 39 ++++++++++++++++++++++
2 files changed, 45 insertions(+), 4 deletions(-)
diff --git a/graphql-scripting/pom.xml b/graphql-scripting/pom.xml
index 9d0727f..7852c61 100644
--- a/graphql-scripting/pom.xml
+++ b/graphql-scripting/pom.xml
@@ -85,13 +85,11 @@
</build>
<dependencies>
- <!-- javax -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>test</scope>
</dependency>
- <!-- OSGi -->
<dependency>
<groupId>org.osgi</groupId>
<artifactId>osgi.cmpn</artifactId>
@@ -112,14 +110,18 @@
<artifactId>org.osgi.service.metatype.annotations</artifactId>
<scope>provided</scope>
</dependency>
- <!-- Apache Felix -->
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.framework</artifactId>
<version>6.0.3</version>
<scope>test</scope>
</dependency>
- <!-- Apache Sling -->
+ <dependency>
+ <groupId>com.graphql-java</groupId>
+ <artifactId>graphql-java</artifactId>
+ <version>11.0</version>
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.api</artifactId>
diff --git a/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/GraphQLScriptingTestSupport.java b/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/GraphQLScriptingTestSupport.java
index 414546a..9ae877b 100644
--- a/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/GraphQLScriptingTestSupport.java
+++ b/graphql-scripting/src/test/java/org/apache/sling/scripting/graphql/it/GraphQLScriptingTestSupport.java
@@ -26,6 +26,7 @@ import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.servlethelpers.MockSlingHttpServletRequest;
import org.apache.sling.servlethelpers.MockSlingHttpServletResponse;
import org.apache.sling.testing.paxexam.TestSupport;
+import org.junit.Before;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.ProbeBuilder;
import org.ops4j.pax.exam.TestProbeBuilder;
@@ -37,6 +38,7 @@ import org.apache.sling.engine.SlingRequestProcessor;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
import static org.apache.sling.testing.paxexam.SlingOptions.slingQuickstartOakTar;
import static org.apache.sling.testing.paxexam.SlingOptions.slingResourcePresence;
import static org.apache.sling.testing.paxexam.SlingOptions.slingScripting;
@@ -47,8 +49,13 @@ import static org.ops4j.pax.exam.CoreOptions.when;
import static org.ops4j.pax.exam.CoreOptions.vmOption;
import static org.ops4j.pax.exam.cm.ConfigurationAdminOptions.newConfiguration;
+import java.util.ArrayList;
+import java.util.List;
+
public abstract class GraphQLScriptingTestSupport extends TestSupport {
+ private final static int STARTUP_WAIT_SECONDS = 30;
+
@Inject
@Filter(value = "(names=graphql)")
protected ScriptEngineFactory scriptEngineFactory;
@@ -68,6 +75,7 @@ public abstract class GraphQLScriptingTestSupport extends TestSupport {
),
super.baseConfiguration(),
slingQuickstart(),
+ graphQLJava(),
testBundle("bundle.filename"),
newConfiguration("org.apache.sling.jcr.base.internal.LoginAdminWhitelist")
.put("whitelist.bundles.regexp", "^PAXEXAM.*$")
@@ -93,6 +101,37 @@ public abstract class GraphQLScriptingTestSupport extends TestSupport {
);
}
+ protected Option graphQLJava() {
+ return composite(
+ mavenBundle().groupId("com.graphql-java").artifactId("graphql-java").versionAsInProject(),
+ mavenBundle().groupId("org.antlr").artifactId("antlr4-runtime").versionAsInProject(),
+ mavenBundle().groupId("com.graphql-java").artifactId("java-dataloader").versionAsInProject(),
+ mavenBundle().groupId("org.reactivestreams").artifactId("reactive-streams").versionAsInProject()
+ );
+ }
+
+ /**
+ * Injecting the appropriate services to wait for would be more elegant but this is very reliable..
+ */
+ @Before
+ public void waitForSling() throws Exception {
+ final int expectedStatus = 200;
+ final List<Integer> statuses = new ArrayList<>();
+ final String path = "/.json";
+ final long endTime = System.currentTimeMillis() + STARTUP_WAIT_SECONDS * 1000;
+
+ while (System.currentTimeMillis() < endTime) {
+ final int status = executeRequest("GET", path, -1).getStatus();
+ statuses.add(status);
+ if (status == expectedStatus) {
+ return;
+ }
+ Thread.sleep(250);
+ }
+
+ fail("Did not get a " + expectedStatus + " status at " + path + " got " + statuses);
+ }
+
protected MockSlingHttpServletResponse executeRequest(final String method, final String path, final int expectedStatus) throws Exception {
final ResourceResolver resourceResolver = resourceResolverFactory.getAdministrativeResourceResolver(null);
assertNotNull("Expecting ResourceResolver", resourceResolver);