You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2022/01/23 13:44:51 UTC

[isis] branch ISIS-2947 updated (23accbb -> c641861)

This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a change to branch ISIS-2947
in repository https://gitbox.apache.org/repos/asf/isis.git.


    from 23accbb  ISIS-2947: springboot graphql now called from demo app (and so fails, as no schemas defined).
     new f7879e8  ISIS-2947: surfaces dummy domain, integrated to isis interaction
     new c641861  ISIS-2947: sets up schema only after metamodel fully introspected.

The 2 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:
 .run/DemoAppWicketJdo.run.xml                      |   9 ++
 .run/DemoAppWicketJpa (with graphiql).run.xml      |  12 ++
 .run/DemoAppWicketJpa.run.xml                      |  11 ++
 .../metamodel/specloader/SpecificationLoader.java  |   2 +
 .../config/application-graphiql.properties         |   1 +
 .../webapp/wicket/jdo/DemoAppWicketJdo.java        |   7 +-
 .../webapp/wicket/jpa/DemoAppWicketJpa.java        |   9 +-
 ...xecutionStrategyResolvingWithinInteraction.java |  35 ++++++
 .../viewer/source/GraphQlServiceForIsis.java       |  37 +++++++
 .../viewer/source/GraphQlSourceForIsis.java        | 123 +++++++++++++++++++++
 .../viewer/spring/GraphQlAutoConfiguration.java    |   1 +
 11 files changed, 244 insertions(+), 3 deletions(-)
 create mode 100644 .run/DemoAppWicketJdo.run.xml
 create mode 100644 .run/DemoAppWicketJpa (with graphiql).run.xml
 create mode 100644 .run/DemoAppWicketJpa.run.xml
 create mode 100644 examples/demo/web/src/main/resources/config/application-graphiql.properties
 create mode 100644 incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/ExecutionStrategyResolvingWithinInteraction.java
 create mode 100644 incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/GraphQlServiceForIsis.java
 create mode 100644 incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/GraphQlSourceForIsis.java

[isis] 01/02: ISIS-2947: surfaces dummy domain, integrated to isis interaction

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch ISIS-2947
in repository https://gitbox.apache.org/repos/asf/isis.git

commit f7879e83050c081fdf83f420ec527796c269c8ed
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Sun Jan 23 12:57:50 2022 +0000

    ISIS-2947: surfaces dummy domain, integrated to isis interaction
---
 .run/DemoAppWicketJdo.run.xml                      |  9 +++
 .run/DemoAppWicketJpa (with graphiql).run.xml      | 12 ++++
 .run/DemoAppWicketJpa.run.xml                      | 11 +++
 .../config/application-graphiql.properties         |  1 +
 .../webapp/wicket/jdo/DemoAppWicketJdo.java        |  7 +-
 .../webapp/wicket/jpa/DemoAppWicketJpa.java        |  9 ++-
 ...xecutionStrategyResolvingWithinInteraction.java | 35 +++++++++
 .../graphql/viewer/source/MyGraphSource.java       | 84 ++++++++++++++++++++++
 .../viewer/source/dummydomain/LeaseRepository.java |  9 +++
 .../viewer/spring/GraphQlAutoConfiguration.java    |  1 +
 10 files changed, 175 insertions(+), 3 deletions(-)

diff --git a/.run/DemoAppWicketJdo.run.xml b/.run/DemoAppWicketJdo.run.xml
new file mode 100644
index 0000000..b2c56ba
--- /dev/null
+++ b/.run/DemoAppWicketJdo.run.xml
@@ -0,0 +1,9 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="DemoAppWicketJdo" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot">
+    <option name="SPRING_BOOT_MAIN_CLASS" value="demoapp.webapp.wicket.jdo.DemoAppWicketJdo" />
+    <option name="ALTERNATIVE_JRE_PATH" />
+    <method v="2">
+      <option name="Make" enabled="true" />
+    </method>
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/.run/DemoAppWicketJpa (with graphiql).run.xml b/.run/DemoAppWicketJpa (with graphiql).run.xml
new file mode 100644
index 0000000..c18886f
--- /dev/null
+++ b/.run/DemoAppWicketJpa (with graphiql).run.xml	
@@ -0,0 +1,12 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="DemoAppWicketJpa (with graphiql)" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot">
+    <module name="demo-wicket-jpa" />
+    <option name="SPRING_BOOT_MAIN_CLASS" value="demoapp.webapp.wicket.jpa.DemoAppWicketJpa" />
+    <option name="ACTIVE_PROFILES" value="graphiql" />
+    <option name="ALTERNATIVE_JRE_PATH" />
+    <option name="SHORTEN_COMMAND_LINE" value="ARGS_FILE" />
+    <method v="2">
+      <option name="Make" enabled="true" />
+    </method>
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/.run/DemoAppWicketJpa.run.xml b/.run/DemoAppWicketJpa.run.xml
new file mode 100644
index 0000000..68ded5b
--- /dev/null
+++ b/.run/DemoAppWicketJpa.run.xml
@@ -0,0 +1,11 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="DemoAppWicketJpa" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot">
+    <module name="demo-wicket-jpa" />
+    <option name="SPRING_BOOT_MAIN_CLASS" value="demoapp.webapp.wicket.jpa.DemoAppWicketJpa" />
+    <option name="ALTERNATIVE_JRE_PATH" />
+    <option name="SHORTEN_COMMAND_LINE" value="ARGS_FILE" />
+    <method v="2">
+      <option name="Make" enabled="true" />
+    </method>
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/examples/demo/web/src/main/resources/config/application-graphiql.properties b/examples/demo/web/src/main/resources/config/application-graphiql.properties
new file mode 100644
index 0000000..1bd50b3
--- /dev/null
+++ b/examples/demo/web/src/main/resources/config/application-graphiql.properties
@@ -0,0 +1 @@
+spring.graphql.graphiql.enabled=true
diff --git a/examples/demo/wicket/jdo/src/main/java/demoapp/webapp/wicket/jdo/DemoAppWicketJdo.java b/examples/demo/wicket/jdo/src/main/java/demoapp/webapp/wicket/jdo/DemoAppWicketJdo.java
index 4dfec7a..6058e51 100644
--- a/examples/demo/wicket/jdo/src/main/java/demoapp/webapp/wicket/jdo/DemoAppWicketJdo.java
+++ b/examples/demo/wicket/jdo/src/main/java/demoapp/webapp/wicket/jdo/DemoAppWicketJdo.java
@@ -78,10 +78,15 @@ public class DemoAppWicketJdo extends SpringBootServletInitializer {
     	IsisPresets.prototyping();
         //IsisPresets.logging(WebRequestCycleForIsis.class, "debug");
 
-        System.setProperty("spring.profiles.active", "demo-jdo");
+        System.setProperty("spring.profiles.active", preservingAnyExisting("demo-jdo"));
 
         SpringApplication.run(new Class[] { DemoAppWicketJdo.class }, args);
 
     }
 
+    private static String preservingAnyExisting(String profile) {
+        val existingProfiles = System.getProperty("spring.profiles.active");
+        return existingProfiles == null ? profile : existingProfiles + "," + profile;
+    }
+
 }
diff --git a/examples/demo/wicket/jpa/src/main/java/demoapp/webapp/wicket/jpa/DemoAppWicketJpa.java b/examples/demo/wicket/jpa/src/main/java/demoapp/webapp/wicket/jpa/DemoAppWicketJpa.java
index adad1d1..39081ed 100644
--- a/examples/demo/wicket/jpa/src/main/java/demoapp/webapp/wicket/jpa/DemoAppWicketJpa.java
+++ b/examples/demo/wicket/jpa/src/main/java/demoapp/webapp/wicket/jpa/DemoAppWicketJpa.java
@@ -33,7 +33,8 @@ import org.apache.isis.valuetypes.markdown.persistence.jpa.IsisModuleValMarkdown
 import org.apache.isis.valuetypes.markdown.ui.wkt.IsisModuleValMarkdownUiWkt;
 import org.apache.isis.valuetypes.sse.ui.wkt.IsisModuleValSseUiWkt;
 import org.apache.isis.viewer.wicket.viewer.IsisModuleViewerWicketViewer;
-import org.apache.isis.viewer.wicket.viewer.registries.components.ComponentFactoryRegistryDefault;
+
+import lombok.val;
 
 import demoapp.web.DemoAppManifestJpa;
 import demoapp.webapp.wicket.common.ui.DemoAppWicketCommon;
@@ -82,12 +83,16 @@ public class DemoAppWicketJpa extends SpringBootServletInitializer {
         //IsisPresets.logging(EntityModel.class, "debug");
         //IsisPresets.logging(FormExecutorDefault.class, "debug");
 
-        System.setProperty("spring.profiles.active", "demo-jpa");
+        System.setProperty("spring.profiles.active", preservingAnyExisting("demo-jpa"));
 
         SpringApplication.run(new Class[] { DemoAppWicketJpa.class }, args);
 
     }
 
+    private static String preservingAnyExisting(String profile) {
+        val existingProfiles = System.getProperty("spring.profiles.active");
+        return existingProfiles == null ? profile : existingProfiles + "," + profile;
+    }
 
 
 }
diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/ExecutionStrategyResolvingWithinInteraction.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/ExecutionStrategyResolvingWithinInteraction.java
new file mode 100644
index 0000000..50bda04
--- /dev/null
+++ b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/ExecutionStrategyResolvingWithinInteraction.java
@@ -0,0 +1,35 @@
+package org.apache.isis.viewer.graphql.viewer.source;
+
+import java.util.concurrent.CompletableFuture;
+
+import javax.inject.Inject;
+
+import org.springframework.stereotype.Service;
+
+import org.apache.isis.applib.services.iactnlayer.InteractionService;
+
+import lombok.RequiredArgsConstructor;
+
+import graphql.execution.AsyncExecutionStrategy;
+import graphql.execution.ExecutionContext;
+import graphql.execution.ExecutionStrategyParameters;
+import graphql.execution.FieldValueInfo;
+
+@Service
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
+public class ExecutionStrategyResolvingWithinInteraction extends AsyncExecutionStrategy {
+
+    private final InteractionService interactionService;
+
+    @Override
+    protected CompletableFuture<FieldValueInfo> resolveFieldWithInfo(ExecutionContext executionContext, ExecutionStrategyParameters parameters) {
+
+        interactionService.openInteraction();
+        try {
+            return super.resolveFieldWithInfo(executionContext, parameters);
+        } finally {
+            interactionService.closeInteractionLayers();
+        }
+
+    }
+}
diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/MyGraphSource.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/MyGraphSource.java
new file mode 100644
index 0000000..18ae6f1
--- /dev/null
+++ b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/MyGraphSource.java
@@ -0,0 +1,84 @@
+package org.apache.isis.viewer.graphql.viewer.source;
+
+import javax.inject.Inject;
+
+import org.springframework.graphql.execution.GraphQlSource;
+import org.springframework.stereotype.Service;
+
+import org.apache.isis.viewer.graphql.viewer.source.dummydomain.LeaseRepository;
+
+import lombok.RequiredArgsConstructor;
+import lombok.val;
+
+import graphql.GraphQL;
+import graphql.Scalars;
+import graphql.execution.AsyncExecutionStrategy;
+import graphql.execution.instrumentation.tracing.TracingInstrumentation;
+import graphql.schema.DataFetcher;
+import graphql.schema.GraphQLCodeRegistry;
+import graphql.schema.GraphQLFieldDefinition;
+import graphql.schema.GraphQLObjectType;
+import graphql.schema.GraphQLSchema;
+import graphql.schema.GraphQLTypeReference;
+
+import static graphql.schema.FieldCoordinates.coordinates;
+
+@Service
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
+public class MyGraphSource implements GraphQlSource {
+
+    private final LeaseRepository leaseRepository;
+    private final ExecutionStrategyResolvingWithinInteraction executionStrategy;
+
+    @Override
+    public GraphQL graphQl() {
+        // val asyncExecutionStrategy = new AsyncExecutionStrategy();
+        return GraphQL.newGraphQL(schema())
+                .instrumentation(new TracingInstrumentation())
+                .queryExecutionStrategy(executionStrategy)
+                .build();
+    }
+
+    @Override
+    public GraphQLSchema schema() {
+
+        // type LeaseRepository {
+        //     numLeases: Int
+        // }
+        val leaseRepository_numLeases = GraphQLFieldDefinition.newFieldDefinition()
+                .name("numLeases")
+                .type(Scalars.GraphQLInt)
+                .build();
+        val leaseRepositoryType = GraphQLObjectType.newObject()
+                .name("LeaseRepository")
+                .field(leaseRepository_numLeases)
+                .build();
+
+        // type Query {
+        //     leaseRepo: LeaseRepository
+        // }
+        val query_leaseRepo = GraphQLFieldDefinition.newFieldDefinition()
+                .name("leaseRepo")
+                .type(GraphQLTypeReference.typeRef(leaseRepositoryType.getName()))
+                .build();
+        GraphQLObjectType query = GraphQLObjectType.newObject()
+                .name("Query")
+                .field(query_leaseRepo)
+                .build();
+
+        val codeRegistry = GraphQLCodeRegistry.newCodeRegistry()
+                .dataFetcher(coordinates(query.getName(), query_leaseRepo.getName()),
+                        (DataFetcher<Object>) environment -> leaseRepository)
+                .dataFetcher(coordinates(leaseRepositoryType.getName(), leaseRepository_numLeases.getName()),
+                        (DataFetcher<Object>) environment -> leaseRepository.numLeases)
+                .build();
+
+
+        return GraphQLSchema.newSchema()
+                .query(query)
+                .additionalType(leaseRepositoryType)
+                .codeRegistry(codeRegistry)
+                .build();
+    }
+
+}
diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/dummydomain/LeaseRepository.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/dummydomain/LeaseRepository.java
new file mode 100644
index 0000000..2aceb33
--- /dev/null
+++ b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/dummydomain/LeaseRepository.java
@@ -0,0 +1,9 @@
+package org.apache.isis.viewer.graphql.viewer.source.dummydomain;
+
+import org.springframework.stereotype.Service;
+
+@Service
+public class LeaseRepository {
+
+    public int numLeases = 5;
+}
diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/spring/GraphQlAutoConfiguration.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/spring/GraphQlAutoConfiguration.java
index e070078..e16fcf43 100644
--- a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/spring/GraphQlAutoConfiguration.java
+++ b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/spring/GraphQlAutoConfiguration.java
@@ -24,6 +24,7 @@ import java.util.stream.Collectors;
 
 import graphql.GraphQL;
 import graphql.execution.instrumentation.Instrumentation;
+import graphql.schema.idl.RuntimeWiring;
 import graphql.schema.visibility.NoIntrospectionGraphqlFieldVisibility;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;

[isis] 02/02: ISIS-2947: sets up schema only after metamodel fully introspected.

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch ISIS-2947
in repository https://gitbox.apache.org/repos/asf/isis.git

commit c641861c9a4cb3143bf3903541c731bd448d6178
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Sun Jan 23 13:44:36 2022 +0000

    ISIS-2947: sets up schema only after metamodel fully introspected.
---
 .../metamodel/specloader/SpecificationLoader.java  |   2 +
 .../viewer/source/GraphQlServiceForIsis.java       |  37 +++++++
 .../viewer/source/GraphQlSourceForIsis.java        | 123 +++++++++++++++++++++
 .../graphql/viewer/source/MyGraphSource.java       |  84 --------------
 .../viewer/source/dummydomain/LeaseRepository.java |   9 --
 5 files changed, 162 insertions(+), 93 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
index a54d242..fec274a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
@@ -18,6 +18,8 @@
  */
 package org.apache.isis.core.metamodel.specloader;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Optional;
 import java.util.function.Consumer;
 
diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/GraphQlServiceForIsis.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/GraphQlServiceForIsis.java
new file mode 100644
index 0000000..260dad7
--- /dev/null
+++ b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/GraphQlServiceForIsis.java
@@ -0,0 +1,37 @@
+package org.apache.isis.viewer.graphql.viewer.source;
+
+import javax.inject.Inject;
+
+import org.springframework.graphql.GraphQlService;
+import org.springframework.graphql.RequestInput;
+import org.springframework.graphql.RequestOutput;
+import org.springframework.graphql.execution.BatchLoaderRegistry;
+import org.springframework.graphql.execution.ExecutionGraphQlService;
+import org.springframework.graphql.execution.GraphQlSource;
+import org.springframework.stereotype.Service;
+
+import lombok.RequiredArgsConstructor;
+
+import reactor.core.publisher.Mono;
+
+/**
+ * Defers calling of {@link GraphQlSourceForIsis#schema()} until after the metamodel is fully introspected.
+ */
+@Service()
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
+public class GraphQlServiceForIsis implements GraphQlService {
+
+    private final BatchLoaderRegistry batchLoaderRegistry;
+    private final GraphQlSource graphQlSource;
+
+    ExecutionGraphQlService delegate;
+
+    @Override
+    public Mono<RequestOutput> execute(RequestInput input) {
+        if(delegate == null) {
+            delegate = new ExecutionGraphQlService(graphQlSource);
+            delegate.addDataLoaderRegistrar(batchLoaderRegistry);
+        }
+        return delegate.execute(input);
+    }
+}
diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/GraphQlSourceForIsis.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/GraphQlSourceForIsis.java
new file mode 100644
index 0000000..82cd012
--- /dev/null
+++ b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/GraphQlSourceForIsis.java
@@ -0,0 +1,123 @@
+package org.apache.isis.viewer.graphql.viewer.source;
+
+import java.util.concurrent.CountDownLatch;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+
+import org.springframework.graphql.execution.GraphQlSource;
+import org.springframework.stereotype.Service;
+
+import org.apache.isis.applib.services.registry.ServiceRegistry;
+import org.apache.isis.core.config.IsisConfiguration;
+import org.apache.isis.core.config.environment.IsisSystemEnvironment;
+import org.apache.isis.core.config.metamodel.specloader.IntrospectionMode;
+import org.apache.isis.core.metamodel.specloader.SpecificationLoaderDefault;
+
+import lombok.RequiredArgsConstructor;
+import lombok.val;
+
+import graphql.GraphQL;
+import graphql.Scalars;
+import graphql.execution.instrumentation.tracing.TracingInstrumentation;
+import graphql.schema.DataFetcher;
+import graphql.schema.GraphQLCodeRegistry;
+import graphql.schema.GraphQLFieldDefinition;
+import graphql.schema.GraphQLObjectType;
+import graphql.schema.GraphQLSchema;
+
+import static graphql.schema.FieldCoordinates.coordinates;
+
+@Service()
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
+public class GraphQlSourceForIsis implements GraphQlSource {
+
+    private final ServiceRegistry serviceRegistry;
+    private final SpecificationLoaderDefault specificationLoader;
+    private final IsisConfiguration isisConfiguration;
+    private final IsisSystemEnvironment isisSystemEnvironment;
+    private final ExecutionStrategyResolvingWithinInteraction executionStrategy;
+
+    private final CountDownLatch countDownLatch = new CountDownLatch(1);
+
+    @PostConstruct
+    public void init() {
+        boolean fullyIntrospect = IntrospectionMode.isFullIntrospect(isisConfiguration, isisSystemEnvironment);
+        if (!fullyIntrospect) {
+            throw new IllegalStateException("GraphQL requires full introspection mode");
+        }
+    }
+
+    @Override
+    public GraphQL graphQl() {
+        return GraphQL.newGraphQL(schema())
+                .instrumentation(new TracingInstrumentation())
+                .queryExecutionStrategy(executionStrategy)
+                .build();
+    }
+
+    @Override
+    public GraphQLSchema schema() {
+
+        val fullyIntrospected = specificationLoader.isMetamodelFullyIntrospected();
+        if(!fullyIntrospected) {
+            throw new IllegalStateException("Metamodel is not fully introspected");
+        }
+
+//        // type LeaseRepository {
+//        //     numLeases: Int
+//        // }
+//        val leaseRepository_numLeases = GraphQLFieldDefinition.newFieldDefinition()
+//                .name("numLeases")
+//                .type(Scalars.GraphQLInt)
+//                .build();
+//        val leaseRepositoryType = GraphQLObjectType.newObject()
+//                .name("LeaseRepository")
+//                .field(leaseRepository_numLeases)
+//                .build();
+
+//        // type Query {
+//        //     leaseRepo: LeaseRepository
+//        // }
+//        val query_leaseRepo = GraphQLFieldDefinition.newFieldDefinition()
+//                .name("leaseRepo")
+//                .type(GraphQLTypeReference.typeRef(leaseRepositoryType.getName()))
+//                .build();
+//        GraphQLObjectType query = GraphQLObjectType.newObject()
+//                .name("Query")
+//                .field(query_leaseRepo)
+//                .build();
+//
+//        val codeRegistry = GraphQLCodeRegistry.newCodeRegistry()
+//                .dataFetcher(coordinates(query.getName(), query_leaseRepo.getName()),
+//                        (DataFetcher<Object>) environment -> leaseRepository)
+//                .dataFetcher(coordinates(leaseRepositoryType.getName(), leaseRepository_numLeases.getName()),
+//                        (DataFetcher<Object>) environment -> leaseRepository.numLeases)
+//                .build();
+
+        // type Query {
+        //     numServices: Int
+        // }
+        val query_numServices = GraphQLFieldDefinition.newFieldDefinition()
+                .name("numServices")
+                .type(Scalars.GraphQLInt)
+                .build();
+        GraphQLObjectType query = GraphQLObjectType.newObject()
+                .name("Query")
+                .field(query_numServices)
+                .build();
+
+
+        val codeRegistry = GraphQLCodeRegistry.newCodeRegistry()
+        .dataFetcher(coordinates(query.getName(), query_numServices.getName()),
+                (DataFetcher<Object>) environment -> this.serviceRegistry.streamRegisteredBeans().count())
+        .build();
+
+        return GraphQLSchema.newSchema()
+                .query(query)
+                // .additionalType(leaseRepositoryType)
+                .codeRegistry(codeRegistry)
+                .build();
+    }
+
+}
diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/MyGraphSource.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/MyGraphSource.java
deleted file mode 100644
index 18ae6f1..0000000
--- a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/MyGraphSource.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package org.apache.isis.viewer.graphql.viewer.source;
-
-import javax.inject.Inject;
-
-import org.springframework.graphql.execution.GraphQlSource;
-import org.springframework.stereotype.Service;
-
-import org.apache.isis.viewer.graphql.viewer.source.dummydomain.LeaseRepository;
-
-import lombok.RequiredArgsConstructor;
-import lombok.val;
-
-import graphql.GraphQL;
-import graphql.Scalars;
-import graphql.execution.AsyncExecutionStrategy;
-import graphql.execution.instrumentation.tracing.TracingInstrumentation;
-import graphql.schema.DataFetcher;
-import graphql.schema.GraphQLCodeRegistry;
-import graphql.schema.GraphQLFieldDefinition;
-import graphql.schema.GraphQLObjectType;
-import graphql.schema.GraphQLSchema;
-import graphql.schema.GraphQLTypeReference;
-
-import static graphql.schema.FieldCoordinates.coordinates;
-
-@Service
-@RequiredArgsConstructor(onConstructor_ = {@Inject})
-public class MyGraphSource implements GraphQlSource {
-
-    private final LeaseRepository leaseRepository;
-    private final ExecutionStrategyResolvingWithinInteraction executionStrategy;
-
-    @Override
-    public GraphQL graphQl() {
-        // val asyncExecutionStrategy = new AsyncExecutionStrategy();
-        return GraphQL.newGraphQL(schema())
-                .instrumentation(new TracingInstrumentation())
-                .queryExecutionStrategy(executionStrategy)
-                .build();
-    }
-
-    @Override
-    public GraphQLSchema schema() {
-
-        // type LeaseRepository {
-        //     numLeases: Int
-        // }
-        val leaseRepository_numLeases = GraphQLFieldDefinition.newFieldDefinition()
-                .name("numLeases")
-                .type(Scalars.GraphQLInt)
-                .build();
-        val leaseRepositoryType = GraphQLObjectType.newObject()
-                .name("LeaseRepository")
-                .field(leaseRepository_numLeases)
-                .build();
-
-        // type Query {
-        //     leaseRepo: LeaseRepository
-        // }
-        val query_leaseRepo = GraphQLFieldDefinition.newFieldDefinition()
-                .name("leaseRepo")
-                .type(GraphQLTypeReference.typeRef(leaseRepositoryType.getName()))
-                .build();
-        GraphQLObjectType query = GraphQLObjectType.newObject()
-                .name("Query")
-                .field(query_leaseRepo)
-                .build();
-
-        val codeRegistry = GraphQLCodeRegistry.newCodeRegistry()
-                .dataFetcher(coordinates(query.getName(), query_leaseRepo.getName()),
-                        (DataFetcher<Object>) environment -> leaseRepository)
-                .dataFetcher(coordinates(leaseRepositoryType.getName(), leaseRepository_numLeases.getName()),
-                        (DataFetcher<Object>) environment -> leaseRepository.numLeases)
-                .build();
-
-
-        return GraphQLSchema.newSchema()
-                .query(query)
-                .additionalType(leaseRepositoryType)
-                .codeRegistry(codeRegistry)
-                .build();
-    }
-
-}
diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/dummydomain/LeaseRepository.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/dummydomain/LeaseRepository.java
deleted file mode 100644
index 2aceb33..0000000
--- a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/dummydomain/LeaseRepository.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.apache.isis.viewer.graphql.viewer.source.dummydomain;
-
-import org.springframework.stereotype.Service;
-
-@Service
-public class LeaseRepository {
-
-    public int numLeases = 5;
-}