UNOMI-392 Integrate GraphQL v14 field visibility with always true by … (#224)

* UNOMI-392 Integrate GraphQL v14 field visibility with always true by default

* UNOMI-392 Integrate GraphQL v14 field visibility with always true by default
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/providers/GraphQLFieldVisibilityProvider.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/providers/GraphQLFieldVisibilityProvider.java
new file mode 100644
index 0000000..a835030
--- /dev/null
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/providers/GraphQLFieldVisibilityProvider.java
@@ -0,0 +1,29 @@
+/*
+ * 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.unomi.graphql.providers;
+
+import graphql.schema.visibility.GraphqlFieldVisibility;
+
+/**
+ *  Provider of {@link GraphqlFieldVisibility} to limit graphql schema fields visibility
+ *  More about it here https://www.graphql-java.com/documentation/v14/fieldvisibility/
+ */
+public interface GraphQLFieldVisibilityProvider extends GraphQLProvider {
+
+    GraphqlFieldVisibility getGraphQLFieldVisibility();
+
+}
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaProvider.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaProvider.java
index 31a23b6..8ea7193 100644
--- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaProvider.java
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaProvider.java
@@ -46,6 +46,7 @@
 import org.apache.unomi.graphql.providers.GraphQLAdditionalTypesProvider;
 import org.apache.unomi.graphql.providers.GraphQLCodeRegistryProvider;
 import org.apache.unomi.graphql.providers.GraphQLExtensionsProvider;
+import org.apache.unomi.graphql.providers.GraphQLFieldVisibilityProvider;
 import org.apache.unomi.graphql.providers.GraphQLMutationProvider;
 import org.apache.unomi.graphql.providers.GraphQLQueryProvider;
 import org.apache.unomi.graphql.providers.GraphQLSubscriptionProvider;
@@ -99,6 +100,8 @@
 
     private final List<GraphQLSubscriptionProvider> subscriptionProviders;
 
+    private final GraphQLFieldVisibilityProvider fieldVisibilityProvider;
+
     private final GraphQLCodeRegistryProvider codeRegistryProvider;
 
     private final UnomiEventPublisher eventPublisher;
@@ -118,6 +121,7 @@
         this.mutationProviders = builder.mutationProviders;
         this.subscriptionProviders = builder.subscriptionProviders;
         this.codeRegistryProvider = builder.codeRegistryProvider;
+        this.fieldVisibilityProvider = builder.fieldVisibilityProvider;
     }
 
     public GraphQLSchema createSchema() {
@@ -139,6 +143,8 @@
 
         transformMutations();
 
+        configureFieldVisibility();
+
         configureCodeRegister();
 
         final AnnotationsSchemaCreator.Builder annotationsSchema = AnnotationsSchemaCreator.newAnnotationsSchema();
@@ -672,6 +678,13 @@
         }
     }
 
+    private void configureFieldVisibility() {
+        if (fieldVisibilityProvider != null) {
+            graphQLAnnotations.getContainer().getCodeRegistryBuilder()
+                    .fieldVisibility(fieldVisibilityProvider.getGraphQLFieldVisibility());
+        }
+    }
+
     public GraphQLInputObjectType getInputObjectType(final Class<?> annotatedClass) {
         return (GraphQLInputObjectType) graphQLAnnotations.getObjectHandler().getTypeRetriever()
                 .getGraphQLType(annotatedClass, graphQLAnnotations.getContainer(), true);
@@ -704,6 +717,8 @@
 
         List<GraphQLSubscriptionProvider> subscriptionProviders;
 
+        GraphQLFieldVisibilityProvider fieldVisibilityProvider;
+
         GraphQLCodeRegistryProvider codeRegistryProvider;
 
         UnomiEventPublisher eventPublisher;
@@ -753,6 +768,11 @@
             return this;
         }
 
+        public Builder fieldVisibilityProvider(GraphQLFieldVisibilityProvider fieldVisibilityProvider) {
+            this.fieldVisibilityProvider = fieldVisibilityProvider;
+            return this;
+        }
+
         void validate() {
             Objects.requireNonNull(profileService, "Profile service can not be null");
         }
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaUpdater.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaUpdater.java
index 58ac373..73a7712 100644
--- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaUpdater.java
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaUpdater.java
@@ -26,6 +26,7 @@
 import org.apache.unomi.graphql.providers.GraphQLAdditionalTypesProvider;
 import org.apache.unomi.graphql.providers.GraphQLCodeRegistryProvider;
 import org.apache.unomi.graphql.providers.GraphQLExtensionsProvider;
+import org.apache.unomi.graphql.providers.GraphQLFieldVisibilityProvider;
 import org.apache.unomi.graphql.providers.GraphQLMutationProvider;
 import org.apache.unomi.graphql.providers.GraphQLProvider;
 import org.apache.unomi.graphql.providers.GraphQLQueryProvider;
@@ -72,6 +73,8 @@
 
     private final List<GraphQLTypeFunctionProvider> typeFunctionProviders = new CopyOnWriteArrayList<>();
 
+    private GraphQLFieldVisibilityProvider fieldVisibilityProvider;
+
     private GraphQLCodeRegistryProvider codeRegistryProvider;
 
     private UnomiEventPublisher eventPublisher;
@@ -161,6 +164,9 @@
         if (provider instanceof GraphQLAdditionalTypesProvider) {
             additionalTypesProviders.add((GraphQLAdditionalTypesProvider) provider);
         }
+        if (provider instanceof GraphQLFieldVisibilityProvider) {
+            fieldVisibilityProvider = (GraphQLFieldVisibilityProvider) provider;
+        }
         if (provider instanceof GraphQLCodeRegistryProvider) {
             codeRegistryProvider = (GraphQLCodeRegistryProvider) provider;
         }
@@ -177,11 +183,11 @@
         if (provider instanceof GraphQLSubscriptionProvider) {
             subscriptionProviders.remove(provider);
         }
-        if (provider instanceof GraphQLSubscriptionProvider) {
-            subscriptionProviders.add((GraphQLSubscriptionProvider) provider);
-        }
         if (provider instanceof GraphQLAdditionalTypesProvider) {
-            additionalTypesProviders.add((GraphQLAdditionalTypesProvider) provider);
+            additionalTypesProviders.remove(provider);
+        }
+        if (provider instanceof GraphQLFieldVisibilityProvider) {
+            fieldVisibilityProvider = null;
         }
         if (provider instanceof GraphQLCodeRegistryProvider) {
             codeRegistryProvider = GraphQLCodeRegistry::newCodeRegistry;
@@ -228,6 +234,20 @@
         updateSchema();
     }
 
+
+    @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
+    public void bindFieldVisibilityProvider(GraphQLFieldVisibilityProvider provider) {
+        fieldVisibilityProvider = provider;
+
+        updateSchema();
+    }
+
+    public void unbindFieldVisibilityProvider(GraphQLFieldVisibilityProvider provider) {
+        fieldVisibilityProvider = null;
+
+        updateSchema();
+    }
+
     @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
     public void bindExtensionsProvider(GraphQLExtensionsProvider provider) {
         extensionsProviders.add(provider);
@@ -319,6 +339,7 @@
                 .subscriptionProviders(subscriptionProviders)
                 .eventPublisher(eventPublisher)
                 .codeRegistryProvider(codeRegistryProvider)
+                .fieldVisibilityProvider(fieldVisibilityProvider)
                 .build();
 
         final GraphQLSchema schema = schemaProvider.createSchema();
diff --git a/samples/graphql-providers/src/main/java/org/apache/unomi/graphql/providers/sample/CDPProviderSample.java b/samples/graphql-providers/src/main/java/org/apache/unomi/graphql/providers/sample/CDPProviderSample.java
index 8fd984c..8f688d4 100644
--- a/samples/graphql-providers/src/main/java/org/apache/unomi/graphql/providers/sample/CDPProviderSample.java
+++ b/samples/graphql-providers/src/main/java/org/apache/unomi/graphql/providers/sample/CDPProviderSample.java
@@ -23,9 +23,12 @@
 import graphql.schema.GraphQLArgument;
 import graphql.schema.GraphQLCodeRegistry;
 import graphql.schema.GraphQLFieldDefinition;
+import graphql.schema.visibility.BlockedFields;
+import graphql.schema.visibility.GraphqlFieldVisibility;
 import org.apache.unomi.graphql.providers.GraphQLAdditionalTypesProvider;
 import org.apache.unomi.graphql.providers.GraphQLCodeRegistryProvider;
 import org.apache.unomi.graphql.providers.GraphQLExtensionsProvider;
+import org.apache.unomi.graphql.providers.GraphQLFieldVisibilityProvider;
 import org.apache.unomi.graphql.providers.GraphQLMutationProvider;
 import org.apache.unomi.graphql.providers.GraphQLProvider;
 import org.apache.unomi.graphql.providers.GraphQLQueryProvider;
@@ -43,7 +46,7 @@
 
 @Component(immediate = true, service = GraphQLProvider.class)
 public class CDPProviderSample
-        implements GraphQLExtensionsProvider, GraphQLMutationProvider, GraphQLQueryProvider, GraphQLCodeRegistryProvider, GraphQLAdditionalTypesProvider {
+        implements GraphQLExtensionsProvider, GraphQLMutationProvider, GraphQLQueryProvider, GraphQLCodeRegistryProvider, GraphQLAdditionalTypesProvider, GraphQLFieldVisibilityProvider {
 
     private boolean isActivated;
 
@@ -137,4 +140,12 @@
         return types;
     }
 
+    @Override
+    public GraphqlFieldVisibility getGraphQLFieldVisibility() {
+        // Blocks fields based on patterns
+        return BlockedFields.newBlock()
+                .addPattern("CDP_SegmentInput.name")
+                .addPattern(".*\\.delete.*") // regular expressions allowed
+                .build();
+    }
 }