Repository: gchq/gaffer
Issue: Problems with getOriginalSchema in Federated and Proxy Stores

Problems have been reported fetching schemas with Federated and Proxy Stores. The current implementation of these stores contain overridden methods for `getSchema` but not `getOriginalSchema`. It's likely that with certain combinations of graphs and stores, the `originalSchema` field could remain `null` or be outdated. This could cause problems with the getSchema operation when used directly on the store (not wrapped) and differences between using a `Store` directly and using it through a `Graph`.

Investigate and fix any problems with Federated and Proxy Store use of `getSchema`/`getOriginalSchema`. This might be as simple as adding overridden methods for `getOriginalSchema`.

**Additional context**
See #2791 for background.


Changed files:
store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToAggregateHandlerTest.java
store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToValidateHandlerTest.java
store-implementation/proxy-store/src/test/java/uk/gov/gchq/gaffer/proxystore/integration/ProxyStoreBasicIT.java
store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/FederatedGraphStorage.java
store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/operation/FederatedOperationChainValidator.java
store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/FederatedStore.java
store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedStoreSchemaTest.java
store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedStoreTest.java
store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/FederatedDelegateToHandler.java
store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToFilterHandlerTest.java
store-implementation/proxy-store/src/main/java/uk/gov/gchq/gaffer/proxystore/ProxyStore.java
store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedGraphStorageTest.java
store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToTransHandlerTest.java
store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/FederatedOperationChainValidatorTest.java
store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/util/FederatedStoreUtil.java

diff --git a/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/FederatedGraphStorage.java b/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/FederatedGraphStorage.java
index 033b3b7c55..1b6aa96e16 100644
--- a/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/FederatedGraphStorage.java
+++ b/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/FederatedGraphStorage.java
@@ -27,17 +27,10 @@ import uk.gov.gchq.gaffer.cache.exception.CacheOperationException;
 import uk.gov.gchq.gaffer.commonutil.JsonUtil;
 import uk.gov.gchq.gaffer.commonutil.exception.OverwritingException;
 import uk.gov.gchq.gaffer.commonutil.pair.Pair;
-import uk.gov.gchq.gaffer.core.exception.GafferRuntimeException;
-import uk.gov.gchq.gaffer.data.elementdefinition.exception.SchemaException;
 import uk.gov.gchq.gaffer.federatedstore.exception.StorageException;
-import uk.gov.gchq.gaffer.federatedstore.operation.FederatedOperation;
 import uk.gov.gchq.gaffer.graph.GraphConfig;
 import uk.gov.gchq.gaffer.graph.GraphSerialisable;
-import uk.gov.gchq.gaffer.store.Context;
 import uk.gov.gchq.gaffer.store.library.GraphLibrary;
-import uk.gov.gchq.gaffer.store.operation.GetSchema;
-import uk.gov.gchq.gaffer.store.schema.Schema;
-import uk.gov.gchq.gaffer.store.schema.Schema.Builder;
 import uk.gov.gchq.gaffer.user.User;
 
 import java.util.ArrayList;
@@ -234,35 +227,6 @@ public class FederatedGraphStorage {
         return Collections.unmodifiableList(rtn);
     }
 
-    @Deprecated
-    public Schema getSchema(final FederatedOperation<Void, Object> operation, final Context context) {
-        if (null == context || null == context.getUser()) {
-            // no user then return an empty schema
-            return new Schema();
-        }
-        final List<String> graphIds = isNull(operation) ? null : operation.getGraphIds();
-
-        final Stream<GraphSerialisable> graphs = getStream(context.getUser(), graphIds);
-        final Builder schemaBuilder = new Builder();
-        try {
-            if (nonNull(operation) && operation.hasPayloadOperation() && operation.payloadInstanceOf(GetSchema.class) && ((GetSchema) operation.getPayloadOperation()).isCompact()) {
-                graphs.forEach(gs -> {
-                    try {
-                        schemaBuilder.merge(gs.getGraph().execute((GetSchema) operation.getPayloadOperation(), context));
-                    } catch (final Exception e) {
-                        throw new GafferRuntimeException("Unable to fetch schema from graph " + gs.getGraphId(), e);
-                    }
-                });
-            } else {
-                graphs.forEach(g -> schemaBuilder.merge(g.getSchema(graphLibrary)));
-            }
-        } catch (final SchemaException e) {
-            final List<String> resultGraphIds = getStream(context.getUser(), graphIds).map(GraphSerialisable::getGraphId).collect(Collectors.toList());
-            throw new SchemaException("Unable to merge the schemas for all of your federated graphs: " + resultGraphIds + ". You can limit which graphs to query for using the FederatedOperation.graphIds option.", e);
-        }
-        return schemaBuilder.build();
-    }
-
     private void validateAllGivenGraphIdsAreVisibleForUser(final User user, final Collection<String> graphIds, final String adminAuth) {
         if (null != graphIds) {
             final Collection<String> visibleIds = getAllIds(user, adminAuth);
diff --git a/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/FederatedStore.java b/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/FederatedStore.java
index c880c5ad4c..70aa2e2d13 100644
--- a/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/FederatedStore.java
+++ b/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/FederatedStore.java
@@ -58,6 +58,7 @@ import uk.gov.gchq.gaffer.federatedstore.util.ApplyViewToElementsFunction;
 import uk.gov.gchq.gaffer.federatedstore.util.MergeSchema;
 import uk.gov.gchq.gaffer.graph.GraphSerialisable;
 import uk.gov.gchq.gaffer.operation.Operation;
+import uk.gov.gchq.gaffer.operation.OperationException;
 import uk.gov.gchq.gaffer.operation.impl.Validate;
 import uk.gov.gchq.gaffer.operation.impl.add.AddElements;
 import uk.gov.gchq.gaffer.operation.impl.function.Aggregate;
@@ -108,7 +109,6 @@ import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreProperties.IS_PUBL
 import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreProperties.STORE_CONFIGURED_GRAPHIDS;
 import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreProperties.STORE_CONFIGURED_MERGE_FUNCTIONS;
 import static uk.gov.gchq.gaffer.federatedstore.util.FederatedStoreUtil.getCleanStrings;
-import static uk.gov.gchq.gaffer.federatedstore.util.FederatedStoreUtil.getFederatedWrappedSchema;
 import static uk.gov.gchq.gaffer.federatedstore.util.FederatedStoreUtil.loadStoreConfiguredGraphIdsListFrom;
 import static uk.gov.gchq.gaffer.federatedstore.util.FederatedStoreUtil.loadStoreConfiguredMergeFunctionMapFrom;
 
@@ -324,34 +324,50 @@ public class FederatedStore extends Store {
     }
 
     /**
-     * Get {@link Schema} for this FederatedStore
+     * This method exists for compatibility only. It will
+     * always return a blank {@link Schema}. Either use the
+     * {@link FederatedStore#getSchema} method and supply a
+     * {@link Context}, or ideally use the {@link GetSchema}
+     * operation instead.
      *
-     * @return schema
+     * @return {@link Schema} blank schema
      */
     @Override
     public Schema getSchema() {
-        return getSchema((Context) null);
+        return getSchema(new Context(), true);
     }
 
     /**
-     * Get {@link Schema} for this FederatedStore
+     * This method exists for compatibility only. It will
+     * always return a blank {@link Schema}. Either use the
+     * {@link FederatedStore#getSchema} method and supply a
+     * {@link Context}, or ideally use the {@link GetSchema}
+     * operation instead.
      *
-     * @param context context with User.
-     * @return schema
+     * @return {@link Schema} blank schema
      */
-    public Schema getSchema(final Context context) {
-        return getSchema(getFederatedWrappedSchema(), context);
+    @Override
+    public Schema getOriginalSchema() {
+        return getSchema(new Context(), false);
     }
 
     /**
-     * Get {@link Schema} for this FederatedStore
+     * Get {@link Schema} for this FederatedStore.
+     * <p>
+     * This will return a merged schema of the original schemas
+     * or the optimised compact schemas of the stores inside
+     * this FederatedStore.
      *
-     * @param operation operation with graphIds.
-     * @param context   context with User.
+     * @param context context with valid User
+     * @param getCompactSchema if true, gets the optimised compact schemas
      * @return schema
      */
-    public Schema getSchema(final FederatedOperation operation, final Context context) {
-        return graphStorage.getSchema(operation, context);
+    public Schema getSchema(final Context context, final boolean getCompactSchema) {
+        try {
+            return execute(new GetSchema.Builder().compact(getCompactSchema).build(), context);
+        } catch (final OperationException e) {
+            throw new GafferRuntimeException("Unable to execute GetSchema Operation", e);
+        }
     }
 
     /**
@@ -589,8 +605,8 @@ public class FederatedStore extends Store {
 
             final List<String> graphIds = new ArrayList<>(storeConfiguredGraphIds);
             final List<String> federatedStoreSystemUser = getAllGraphIds(new User.Builder()
-                    .userId(FEDERATED_STORE_SYSTEM_USER)
-                    .opAuths(this.getProperties().getAdminAuth()).build(),
+                            .userId(FEDERATED_STORE_SYSTEM_USER)
+                            .opAuths(this.getProperties().getAdminAuth()).build(),
                     true);
             graphIds.retainAll(federatedStoreSystemUser);
 
diff --git a/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/operation/FederatedOperationChainValidator.java b/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/operation/FederatedOperationChainValidator.java
index d7f8b9c851..c1bc7dfb5b 100644
--- a/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/operation/FederatedOperationChainValidator.java
+++ b/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/operation/FederatedOperationChainValidator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2022 Crown Copyright
+ * Copyright 2016-2023 Crown Copyright
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,13 +16,16 @@
 
 package uk.gov.gchq.gaffer.federatedstore.operation;
 
+import uk.gov.gchq.gaffer.core.exception.GafferRuntimeException;
 import uk.gov.gchq.gaffer.data.elementdefinition.view.View;
 import uk.gov.gchq.gaffer.federatedstore.FederatedStore;
 import uk.gov.gchq.gaffer.graph.GraphSerialisable;
 import uk.gov.gchq.gaffer.operation.Operation;
+import uk.gov.gchq.gaffer.operation.OperationException;
 import uk.gov.gchq.gaffer.store.Context;
 import uk.gov.gchq.gaffer.store.Store;
 import uk.gov.gchq.gaffer.store.StoreTrait;
+import uk.gov.gchq.gaffer.store.operation.GetSchema;
 import uk.gov.gchq.gaffer.store.operation.OperationChainValidator;
 import uk.gov.gchq.gaffer.store.schema.Schema;
 import uk.gov.gchq.gaffer.store.schema.ViewValidator;
@@ -35,7 +38,6 @@ import java.util.List;
 import java.util.stream.Collectors;
 
 import static java.util.Objects.nonNull;
-import static uk.gov.gchq.gaffer.federatedstore.util.FederatedStoreUtil.getFederatedWrappedSchema;
 import static uk.gov.gchq.gaffer.federatedstore.util.FederatedStoreUtil.shallowCloneWithDeepOptions;
 
 /**
@@ -51,9 +53,13 @@ public class FederatedOperationChainValidator extends OperationChainValidator {
 
     @Override
     protected Schema getSchema(final Operation op, final User user, final Store store) {
-        return (op instanceof FederatedOperation)
-                ? ((FederatedStore) store).getSchema(getFederatedWrappedSchema().graphIds(((FederatedOperation) op).getGraphIds()), new Context(user))
-                : ((FederatedStore) store).getSchema(getFederatedWrappedSchema(), new Context(user));
+        try {
+            return (op instanceof FederatedOperation)
+                    ? store.execute(new FederatedOperation.Builder().<Void, Schema>op(new GetSchema()).graphIds(((FederatedOperation<?, ?>) op).getGraphIds()).build(), new Context(user))
+                    : store.execute(new GetSchema(), new Context(user));
+        } catch (final OperationException e) {
+            throw new GafferRuntimeException("Unable to execute GetSchema Operation", e);
+        }
     }
 
     @Override
diff --git a/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/FederatedDelegateToHandler.java b/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/FederatedDelegateToHandler.java
index 7df3243ad5..fc55f365b3 100644
--- a/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/FederatedDelegateToHandler.java
+++ b/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/FederatedDelegateToHandler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 Crown Copyright
+ * Copyright 2022-2023 Crown Copyright
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@ public class FederatedDelegateToHandler implements OutputOperationHandler<InputO
                 || ValidateHandler.class.isAssignableFrom(handler.getClass())
                 || AggregateHandler.class.isAssignableFrom(handler.getClass())) {
             // Use the doOperation which requires a schema.
-            return (Iterable<? extends Element>) ((OperationWithSchemaHandler) handler).doOperation(operation, ((FederatedStore) store).getSchema(context));
+            return (Iterable<? extends Element>) ((OperationWithSchemaHandler) handler).doOperation(operation, ((FederatedStore) store).getSchema(context, true));
         } else {
             return handler.doOperation(operation, context, store);
         }
diff --git a/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/util/FederatedStoreUtil.java b/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/util/FederatedStoreUtil.java
index 5732b983b8..b36bb9101d 100644
--- a/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/util/FederatedStoreUtil.java
+++ b/store-implementation/federated-store/src/main/java/uk/gov/gchq/gaffer/federatedstore/util/FederatedStoreUtil.java
@@ -280,11 +280,6 @@ public final class FederatedStoreUtil {
         return deprecatedGraphIds;
     }
 
-    @Deprecated
-    public static FederatedOperation<Void, Iterable<Schema>> getFederatedWrappedSchema() {
-        return new FederatedOperation.Builder().<Void, Iterable<Schema>>op(new GetSchema()).build();
-    }
-
     /**
      * Return a clone of the given operations with a deep clone of options.
      * <p>
diff --git a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedGraphStorageTest.java b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedGraphStorageTest.java
index af1054900d..e4499db2ab 100644
--- a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedGraphStorageTest.java
+++ b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedGraphStorageTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017-2022 Crown Copyright
+ * Copyright 2017-2023 Crown Copyright
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -50,7 +50,6 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.Mockito.mock;
 import static uk.gov.gchq.gaffer.federatedstore.FederatedGraphStorage.GRAPH_IDS_NOT_VISIBLE;
@@ -60,9 +59,6 @@ import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.EDGES;
 import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.ENTITIES;
 import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.GRAPH_ID_ACCUMULO;
 import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.STRING;
-import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.contextAuthUser;
-import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.contextBlankUser;
-import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.contextTestUser;
 import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.loadAccumuloStoreProperties;
 import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.resetForFederatedTests;
 import static uk.gov.gchq.gaffer.store.TestTypes.DIRECTED_EITHER;
@@ -295,82 +291,6 @@ public class FederatedGraphStorageTest {
                 .withMessage(String.format(GRAPH_IDS_NOT_VISIBLE, singleton(X)));
     }
 
-    @Test
-    @Deprecated // TODO FS move to FedSchema Tests, when getSchema is deleted
-    public void shouldChangeSchemaWhenAddingGraphB() throws Exception {
-        //given
-        graphStorage.put(graphSerialisableA, auth1Access);
-        final Schema schemaA = graphStorage.getSchema(null, contextTestUser());
-        assertEquals(1, schemaA.getTypes().size());
-        assertEquals(String.class, schemaA.getType(STRING + 1).getClazz());
-        assertEquals(getEntityDefinition(1), schemaA.getElement(ENTITIES + 1));
-        graphStorage.put(graphSerialisableB, auth1Access);
-        final Schema schemaAB = graphStorage.getSchema(null, contextTestUser());
-        assertNotEquals(schemaA, schemaAB);
-        assertEquals(2, schemaAB.getTypes().size());
-        assertEquals(String.class, schemaAB.getType(STRING + 1).getClazz());
-        assertEquals(String.class, schemaAB.getType(STRING + 2).getClazz());
-        assertEquals(getEntityDefinition(1), schemaAB.getElement(ENTITIES + 1));
-        assertEquals(getEntityDefinition(2), schemaAB.getElement(ENTITIES + 2));
-    }
-
-
-    @Test
-    @Deprecated // TODO FS move to FedSchema Tests, when getSchema is deleted
-    public void shouldGetSchemaForOwningUser() throws Exception {
-        graphStorage.put(graphSerialisableA, auth1Access);
-        graphStorage.put(graphSerialisableB, new FederatedAccess(singleton(X), X));
-        final Schema schema = graphStorage.getSchema(null, contextTestUser());
-        assertNotEquals(2, schema.getTypes().size(), "Revealing hidden schema");
-        assertEquals(1, schema.getTypes().size());
-        assertEquals(String.class, schema.getType(STRING + 1).getClazz());
-        assertEquals(getEntityDefinition(1), schema.getElement(ENTITIES + 1));
-    }
-
-    @Test
-    @Deprecated // TODO FS move to FedSchema Tests, when getSchema is deleted
-    public void shouldNotGetSchemaForOwningUserWhenBlockingReadAccessPredicateConfigured() throws Exception {
-        graphStorage.put(graphSerialisableA, blockingReadAccess);
-        graphStorage.put(graphSerialisableB, new FederatedAccess(singleton(X), X));
-        final Schema schema = graphStorage.getSchema(null, contextTestUser());
-        assertNotEquals(2, schema.getTypes().size(), "Revealing hidden schema");
-        assertEquals(0, schema.getTypes().size(), "Revealing hidden schema");
-    }
-
-    @Test
-    @Deprecated // TODO FS move to FedSchema Tests, when getSchema is deleted
-    public void shouldGetSchemaForAuthUser() throws Exception {
-        graphStorage.put(graphSerialisableA, auth1Access);
-        graphStorage.put(graphSerialisableB, new FederatedAccess(singleton(X), X));
-        final Schema schema = graphStorage.getSchema(null, contextAuthUser());
-        assertNotEquals(2, schema.getTypes().size(), "Revealing hidden schema");
-        assertEquals(1, schema.getTypes().size());
-        assertEquals(String.class, schema.getType(STRING + 1).getClazz());
-        assertEquals(getEntityDefinition(1), schema.getElement(ENTITIES + 1));
-    }
-
-    @Test
-    @Deprecated // TODO FS move to FedSchema Tests, when getSchema is deleted
-    public void shouldNotGetSchemaForBlankUser() throws Exception {
-        graphStorage.put(graphSerialisableA, auth1Access);
-        graphStorage.put(graphSerialisableB, new FederatedAccess(singleton(X), X));
-        final Schema schema = graphStorage.getSchema(null, contextBlankUser());
-        assertNotEquals(2, schema.getTypes().size(), "Revealing hidden schema");
-        assertEquals(0, schema.getTypes().size(), "Revealing hidden schema");
-    }
-
-    @Test
-    @Deprecated // TODO FS move to FedSchema Tests, when getSchema is deleted
-    public void shouldGetSchemaForBlankUserWhenPermissiveReadAccessPredicateConfigured() throws Exception {
-        graphStorage.put(graphSerialisableA, permissiveReadAccess);
-        graphStorage.put(graphSerialisableB, new FederatedAccess(singleton(X), X));
-        final Schema schema = graphStorage.getSchema(null, contextBlankUser());
-        assertNotEquals(2, schema.getTypes().size(), "Revealing hidden schema");
-        assertEquals(1, schema.getTypes().size());
-        assertEquals(String.class, schema.getType(STRING + 1).getClazz());
-        assertEquals(getEntityDefinition(1), schema.getElement(ENTITIES + 1));
-    }
-
     @Test
     public void shouldRemoveForOwningUser() throws Exception {
         //given
diff --git a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedStoreSchemaTest.java b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedStoreSchemaTest.java
index 6eb7904ed9..38957ba4c4 100644
--- a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedStoreSchemaTest.java
+++ b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedStoreSchemaTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017-2022 Crown Copyright
+ * Copyright 2017-2023 Crown Copyright
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,6 +19,9 @@ package uk.gov.gchq.gaffer.federatedstore;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
+import uk.gov.gchq.gaffer.access.predicate.AccessPredicate;
+import uk.gov.gchq.gaffer.access.predicate.NoAccessPredicate;
+import uk.gov.gchq.gaffer.access.predicate.UnrestrictedAccessPredicate;
 import uk.gov.gchq.gaffer.accumulostore.AccumuloProperties;
 import uk.gov.gchq.gaffer.data.element.Edge;
 import uk.gov.gchq.gaffer.data.element.Element;
@@ -47,8 +50,10 @@ import uk.gov.gchq.koryphe.impl.predicate.IsEqual;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.Set;
 import java.util.stream.Collectors;
 
+import static java.util.Collections.singleton;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.ACCUMULO_STORE_SINGLE_USE_PROPERTIES;
@@ -71,6 +76,9 @@ import static uk.gov.gchq.gaffer.federatedstore.FederatedStoreTestUtil.resetForF
 import static uk.gov.gchq.gaffer.federatedstore.util.FederatedStoreUtil.getDefaultMergeFunction;
 import static uk.gov.gchq.gaffer.federatedstore.util.FederatedStoreUtil.getFederatedOperation;
 import static uk.gov.gchq.gaffer.store.TestTypes.DIRECTED_EITHER;
+import static uk.gov.gchq.gaffer.user.StoreUser.AUTH_1;
+import static uk.gov.gchq.gaffer.user.StoreUser.authUser;
+import static uk.gov.gchq.gaffer.user.StoreUser.blankUser;
 import static uk.gov.gchq.gaffer.user.StoreUser.testUser;
 
 public class FederatedStoreSchemaTest {
@@ -263,6 +271,133 @@ public class FederatedStoreSchemaTest {
                 .isTrue();
     }
 
+    @Test
+    public void shouldGetSchemaWithOperationAndMethodWithContext() throws OperationException {
+        // Given
+        addGraphWith(GRAPH_ID_A, STRING_TYPE, PROPERTY_1);
+
+        // When
+        final Schema schemaFromOperation = federatedStore.execute(new GetSchema.Builder().build(), testContext);
+        final Schema schemaFromStore = federatedStore.getSchema(testContext, false);
+
+        // Then
+        assertThat(schemaFromOperation).isEqualTo(schemaFromStore);
+    }
+
+    @Test
+    public void shouldGetBlankSchemaWhenUsingDefaultMethod() throws OperationException {
+        // Given
+        addGraphWith(GRAPH_ID_A, STRING_TYPE, PROPERTY_1);
+
+        // When
+        final Schema schemaFromStoreMethod = federatedStore.getOriginalSchema(); // No Context, results in blank schema returned
+
+        // Then
+        assertThat(schemaFromStoreMethod).isEqualTo(new Schema());
+    }
+
+    @Test
+    public void shouldGetSchemaWhenUsingDefaultMethodWhenPermissiveReadAccessPredicateConfigured() throws OperationException {
+        // Given
+        addGraphWithContextAndAccess(GRAPH_ID_A, STRING_TYPE, GROUP_BASIC_EDGE, testContext, new UnrestrictedAccessPredicate(), PROPERTY_1);
+
+        // When
+        final Schema schemaFromStoreMethod = federatedStore.getOriginalSchema();
+
+        // Then
+        assertThat(schemaFromStoreMethod.getEdge(GROUP_BASIC_EDGE).getProperties()).contains(PROPERTY_1);
+    }
+
+    @Test
+    public void shouldChangeSchemaWhenAddingGraphB() throws OperationException {
+        // Given
+        addGraphWith(GRAPH_ID_A, STRING_TYPE, PROPERTY_1);
+
+        // When
+        final Schema schemaA = federatedStore.getSchema(testContext, false);
+
+        // Then
+        assertThat(schemaA.getTypes().size()).isEqualTo(2);
+        assertThat(schemaA.getType(STRING).getClazz()).isEqualTo(String.class);
+        assertThat(schemaA.getEdge(GROUP_BASIC_EDGE).getProperties().size()).isEqualTo(1);
+
+        // Given
+        addGraphWith(GRAPH_ID_B, STRING_REQUIRED_TYPE, PROPERTY_2);
+
+        // When
+        final Schema schemaAB = federatedStore.getSchema(testContext, false);
+
+        // Then
+        assertThat(schemaAB).isNotEqualTo(schemaA);
+        assertThat(schemaAB.getEdge(GROUP_BASIC_EDGE).getProperties()).contains(PROPERTY_2);
+    }
+
+    @Test
+    public void shouldGetSchemaForOwningUser() throws OperationException {
+        // Given
+        addGraphWith(GRAPH_ID_A, STRING_REQUIRED_TYPE, PROPERTY_1);
+        addGraphWithContextAndAuths(GRAPH_ID_B, STRING_TYPE, "hidden" + GROUP_BASIC_EDGE, singleton(AUTH_1), new Context(authUser()), PROPERTY_2);
+
+        // When
+        final Schema schemaFromOwningUser = federatedStore.getSchema(testContext, false);
+
+        // Then
+        assertThat(schemaFromOwningUser.getEdge("hidden" + GROUP_BASIC_EDGE)).withFailMessage("Revealing hidden schema").isNull();
+        assertThat(schemaFromOwningUser.getEdge(GROUP_BASIC_EDGE).getProperties()).contains(PROPERTY_1);
+    }
+
+    @Test
+    public void shouldNotGetSchemaForOwningUserWhenBlockingReadAccessPredicateConfigured() throws OperationException {
+        // Given
+        addGraphWithContextAndAccess(GRAPH_ID_A, STRING_TYPE, GROUP_BASIC_EDGE, testContext, new NoAccessPredicate(), PROPERTY_1);
+
+        // When
+        final Schema schemaFromOwningUser = federatedStore.getSchema(testContext, false);
+
+        // Then
+        assertThat(schemaFromOwningUser).withFailMessage("Revealing blocked schema, should be empty").isEqualTo(new Schema());
+    }
+
+    @Test
+    public void shouldGetSchemaForAuthUser() throws OperationException {
+        // Given
+        final User authUser = new User.Builder().userId("authUser2").opAuths(AUTH_1).build();
+        addGraphWithContextAndAuths(GRAPH_ID_B, STRING_TYPE, GROUP_BASIC_EDGE, singleton(AUTH_1), new Context(authUser()), PROPERTY_1);
+
+        // When
+        final Schema schemaFromAuthUser = federatedStore.getSchema(new Context(authUser), false);
+        final Schema schemaFromTestUser = federatedStore.getSchema(testContext, false);
+
+        // Then
+        assertThat(schemaFromTestUser.getEdge("hidden" + GROUP_BASIC_EDGE)).withFailMessage("Revealing hidden schema").isNull();
+        assertThat(schemaFromTestUser).withFailMessage("Revealing hidden schema, should be empty").isEqualTo(new Schema());
+        assertThat(schemaFromAuthUser.getEdge(GROUP_BASIC_EDGE).getProperties()).contains(PROPERTY_1);
+    }
+
+    @Test
+    public void shouldNotGetSchemaForBlankUser() throws OperationException {
+        // Given
+        addGraphWith(GRAPH_ID_A, STRING_REQUIRED_TYPE, PROPERTY_1);
+
+        // When
+        final Schema schemaFromBlankUser = federatedStore.getSchema(new Context(blankUser()), false);
+
+        // Then
+        assertThat(schemaFromBlankUser).withFailMessage("Revealing schema to blank user, should be empty").isEqualTo(new Schema());
+    }
+
+    @Test
+    public void shouldGetSchemaForBlankUserWhenPermissiveReadAccessPredicateConfigured() throws OperationException {
+        // Given
+        addGraphWithContextAndAccess(GRAPH_ID_A, STRING_TYPE, GROUP_BASIC_EDGE, testContext, new UnrestrictedAccessPredicate(), PROPERTY_1);
+
+        // When
+        final Schema schemaFromBlankUser = federatedStore.getSchema(new Context(blankUser()), false);
+
+        // Then
+        assertThat(schemaFromBlankUser.getEdge(GROUP_BASIC_EDGE).getProperties()).contains(PROPERTY_1);
+    }
+
     @Test
     public void shouldValidateCorrectlyWithOverlappingSchemasUsingDefaultMergeFunction() throws OperationException {
         // Given
@@ -788,11 +923,11 @@ public class FederatedStoreSchemaTest {
         addGraphWith(GRAPH_ID_B, stringSchema, PROPERTY_1, PROPERTY_2);
     }
 
-    private void addGraphWith(final String graphId, final Schema stringType, final String... property) throws OperationException {
-        federatedStore.execute(new AddGraph.Builder()
+    private AddGraph.Builder getAddGraphBuilder(final String graphId, final Schema stringType, final String edgeGroup, final String... property) {
+        return new AddGraph.Builder()
                 .graphId(graphId)
                 .schema(new Schema.Builder()
-                        .edge(GROUP_BASIC_EDGE, new SchemaEdgeDefinition.Builder()
+                        .edge(edgeGroup, new SchemaEdgeDefinition.Builder()
                                 .source(STRING)
                                 .destination(STRING)
                                 .directed(DIRECTED_EITHER)
@@ -801,10 +936,28 @@ public class FederatedStoreSchemaTest {
                         .type(DIRECTED_EITHER, Boolean.class)
                         .merge(stringType)
                         .build())
-                .storeProperties(STORE_PROPERTIES.clone())
+                .storeProperties(STORE_PROPERTIES.clone());
+    }
+
+    private void addGraphWith(final String graphId, final Schema stringType, final String... property) throws OperationException {
+        federatedStore.execute(getAddGraphBuilder(graphId, stringType, GROUP_BASIC_EDGE, property)
                 .build(), testContext);
     }
 
+    private void addGraphWithContextAndAuths(final String graphId, final Schema stringType, final String edgeGroup, Set<String> graphAuths,
+                                             Context context, final String... property) throws OperationException {
+        federatedStore.execute(getAddGraphBuilder(graphId, stringType, edgeGroup, property)
+                .graphAuths(graphAuths.toArray(new String[0]))
+                .build(), context);
+    }
+
+    private void addGraphWithContextAndAccess(final String graphId, final Schema stringType, final String edgeGroup, Context context,
+                                              AccessPredicate read, final String... property) throws OperationException {
+        federatedStore.execute(getAddGraphBuilder(graphId, stringType, edgeGroup, property)
+                .readAccessPredicate(read)
+                .build(), context);
+    }
+
     private void addEdgeBasicWith(final String destination, final Integer... propertyValues) throws OperationException {
         federatedStore.execute(new AddElements.Builder()
                 .input(edgeBasicWith(destination, propertyValues))
diff --git a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedStoreTest.java b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedStoreTest.java
index 5da3e90a41..5873d7d286 100644
--- a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedStoreTest.java
+++ b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/FederatedStoreTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017-2022 Crown Copyright
+ * Copyright 2017-2023 Crown Copyright
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -323,9 +323,9 @@ public class FederatedStoreTest {
     public void shouldUpdateSchemaWhenNewGraphIsAdded() throws Exception {
         // Given
         addGraphWithPaths(ACC_ID_1, propertiesAlt, blankUserContext, SCHEMA_ENTITY_BASIC_JSON);
-        final Schema before = store.getSchema(new Context(blankUser));
+        final Schema before = store.getSchema(new Context(blankUser), true);
         addGraphWithPaths(ACC_ID_2, propertiesAlt, blankUserContext, SCHEMA_EDGE_BASIC_JSON);
-        final Schema after = store.getSchema(new Context(blankUser));
+        final Schema after = store.getSchema(new Context(blankUser), true);
         // Then
         assertThat(before).isNotEqualTo(after);
     }
@@ -335,15 +335,15 @@ public class FederatedStoreTest {
     public void shouldUpdateSchemaWhenNewGraphIsRemoved() throws Exception {
         // Given
         addGraphWithPaths(ACC_ID_1, propertiesAlt, blankUserContext, SCHEMA_ENTITY_BASIC_JSON);
-        final Schema was = store.getSchema(new Context(blankUser));
+        final Schema was = store.getSchema(new Context(blankUser), true);
         addGraphWithPaths(ACC_ID_2, propertiesAlt, blankUserContext, SCHEMA_EDGE_BASIC_JSON);
 
-        final Schema before = store.getSchema(new Context(blankUser));
+        final Schema before = store.getSchema(new Context(blankUser), true);
 
         // When
         store.remove(ACC_ID_2, blankUser);
 
-        final Schema after = store.getSchema(new Context(blankUser));
+        final Schema after = store.getSchema(new Context(blankUser), true);
         assertThat(before).isNotEqualTo(after);
         assertThat(was).isEqualTo(after);
     }
@@ -1160,8 +1160,8 @@ public class FederatedStoreTest {
         final Iterable<? extends Element> elements = store
                 .execute(new GetAllElements.Builder()
                         .view(new View.Builder()
-                                .edges(store.getSchema(context).getEdgeGroups()) //here
-                                .entities(store.getSchema(context).getEntityGroups()) //here 59 -> 58
+                                .edges(store.getSchema(context, true).getEdgeGroups()) //here
+                                .entities(store.getSchema(context, true).getEntityGroups()) //here 59 -> 58
                                 .build())
                         .build(), context);
 
diff --git a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/FederatedOperationChainValidatorTest.java b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/FederatedOperationChainValidatorTest.java
index 13117e8053..fb5aa9793b 100644
--- a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/FederatedOperationChainValidatorTest.java
+++ b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/FederatedOperationChainValidatorTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017-2022 Crown Copyright
+ * Copyright 2017-2023 Crown Copyright
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@ import uk.gov.gchq.gaffer.operation.Operation;
 import uk.gov.gchq.gaffer.operation.OperationException;
 import uk.gov.gchq.gaffer.operation.impl.get.GetAllElements;
 import uk.gov.gchq.gaffer.store.Context;
+import uk.gov.gchq.gaffer.store.operation.GetSchema;
 import uk.gov.gchq.gaffer.store.schema.Schema;
 import uk.gov.gchq.gaffer.store.schema.ViewValidator;
 import uk.gov.gchq.gaffer.user.User;
@@ -37,16 +38,14 @@ import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static uk.gov.gchq.gaffer.federatedstore.util.FederatedStoreUtil.getFederatedOperation;
-import static uk.gov.gchq.gaffer.federatedstore.util.FederatedStoreUtil.getFederatedWrappedSchema;
 
 public class FederatedOperationChainValidatorTest {
     @Test
-    public void shouldGetFederatedSchema() {
+    public void shouldGetFederatedSchema() throws OperationException {
         // Given
         final ViewValidator viewValidator = mock(FederatedViewValidator.class);
         final FederatedOperationChainValidator validator = new FederatedOperationChainValidator(viewValidator);
@@ -54,18 +53,18 @@ public class FederatedOperationChainValidatorTest {
         final User user = mock(User.class);
         final Operation op = mock(Operation.class);
         final Schema schema = mock(Schema.class);
-        given(store.getSchema(eq(getFederatedWrappedSchema()), any(Context.class))).willReturn(schema);
+        given(store.execute(any(GetSchema.class), any(Context.class))).willReturn(schema);
 
         // When
         final Schema actualSchema = validator.getSchema(op, user, store);
 
-        verify(store).getSchema(eq(getFederatedWrappedSchema()), any(Context.class));
+        verify(store).execute(any(GetSchema.class), any(Context.class));
         // Then
         assertEquals(schema, actualSchema);
     }
 
     @Test
-    public void shouldNotErrorWithInvalidViewFromMissingGraph() throws OperationException {
+    public void shouldNotErrorWithInvalidViewFromMissingGraph() {
         //given
         String missingGraph = "missingGraph";
         final Graph graph = new Graph.Builder()
diff --git a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToAggregateHandlerTest.java b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToAggregateHandlerTest.java
index 598d672355..41e38f1181 100644
--- a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToAggregateHandlerTest.java
+++ b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToAggregateHandlerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2022 Crown Copyright
+ * Copyright 2016-2023 Crown Copyright
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -74,7 +74,7 @@ public class FederatedDelegateToAggregateHandlerTest {
                                         @Mock final Schema schema)
             throws OperationException {
         // Given
-        given(store.getSchema(context)).willReturn(schema);
+        given(store.getSchema(context, true)).willReturn(schema);
         given(handler.doOperation(op, schema)).willReturn((Iterable) expectedResult);
 
         final FederatedDelegateToHandler federatedHandler = new FederatedDelegateToHandler(handler);
diff --git a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToFilterHandlerTest.java b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToFilterHandlerTest.java
index f456176e8a..41a50f0d6a 100644
--- a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToFilterHandlerTest.java
+++ b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToFilterHandlerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2022 Crown Copyright
+ * Copyright 2016-2023 Crown Copyright
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -42,7 +42,7 @@ public class FederatedDelegateToFilterHandlerTest {
         final Iterable expectedResult = mock(Iterable.class);
         final Schema schema = mock(Schema.class);
 
-        given(store.getSchema(context)).willReturn(schema);
+        given(store.getSchema(context, true)).willReturn(schema);
         given(handler.doOperation(op, schema)).willReturn(expectedResult);
 
         final FederatedDelegateToHandler federatedHandler = new FederatedDelegateToHandler(handler);
@@ -53,6 +53,6 @@ public class FederatedDelegateToFilterHandlerTest {
         // Then
         assertSame(expectedResult, result);
         verify(handler).doOperation(op, schema);
-        verify(store).getSchema(context);
+        verify(store).getSchema(context, true);
     }
 }
diff --git a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToTransHandlerTest.java b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToTransHandlerTest.java
index a9a5eaf3f0..3f8e2a2b07 100644
--- a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToTransHandlerTest.java
+++ b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToTransHandlerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2022 Crown Copyright
+ * Copyright 2016-2023 Crown Copyright
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -42,7 +42,7 @@ public class FederatedDelegateToTransHandlerTest {
         final Iterable expectedResult = mock(Iterable.class);
         final Schema schema = mock(Schema.class);
 
-        given(store.getSchema(context)).willReturn(schema);
+        given(store.getSchema(context, true)).willReturn(schema);
         given(handler.doOperation(op, schema)).willReturn(expectedResult);
 
         final FederatedDelegateToHandler federatedHandler = new FederatedDelegateToHandler(handler);
@@ -53,6 +53,6 @@ public class FederatedDelegateToTransHandlerTest {
         // Then
         assertSame(expectedResult, result);
         verify(handler).doOperation(op, schema);
-        verify(store).getSchema(context);
+        verify(store).getSchema(context, true);
     }
 }
diff --git a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToValidateHandlerTest.java b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToValidateHandlerTest.java
index 22657ab93b..0cc2425353 100644
--- a/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToValidateHandlerTest.java
+++ b/store-implementation/federated-store/src/test/java/uk/gov/gchq/gaffer/federatedstore/operation/handler/impl/FederatedDelegateToValidateHandlerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-2022 Crown Copyright
+ * Copyright 2016-2023 Crown Copyright
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -42,7 +42,7 @@ public class FederatedDelegateToValidateHandlerTest {
         final Iterable expectedResult = mock(Iterable.class);
         final Schema schema = mock(Schema.class);
 
-        given(store.getSchema(context)).willReturn(schema);
+        given(store.getSchema(context, true)).willReturn(schema);
         given(handler.doOperation(op, schema)).willReturn(expectedResult);
 
         final FederatedDelegateToHandler federatedHandler = new FederatedDelegateToHandler(handler);
diff --git a/store-implementation/proxy-store/src/main/java/uk/gov/gchq/gaffer/proxystore/ProxyStore.java b/store-implementation/proxy-store/src/main/java/uk/gov/gchq/gaffer/proxystore/ProxyStore.java
index 81d27b2b2c..61026697b9 100644
--- a/store-implementation/proxy-store/src/main/java/uk/gov/gchq/gaffer/proxystore/ProxyStore.java
+++ b/store-implementation/proxy-store/src/main/java/uk/gov/gchq/gaffer/proxystore/ProxyStore.java
@@ -54,6 +54,7 @@ import uk.gov.gchq.gaffer.store.StoreException;
 import uk.gov.gchq.gaffer.store.StoreProperties;
 import uk.gov.gchq.gaffer.store.StoreTrait;
 import uk.gov.gchq.gaffer.store.TypeReferenceStoreImpl;
+import uk.gov.gchq.gaffer.store.operation.GetSchema;
 import uk.gov.gchq.gaffer.store.operation.GetTraits;
 import uk.gov.gchq.gaffer.store.operation.handler.GetTraitsHandler;
 import uk.gov.gchq.gaffer.store.operation.handler.OperationHandler;
@@ -86,8 +87,8 @@ import static java.util.Objects.nonNull;
  */
 public class ProxyStore extends Store {
     private static final Logger LOGGER = LoggerFactory.getLogger(ProxyStore.class);
+    public static final String ERROR_FETCHING_SCHEMA_FROM_REMOTE_STORE = "Error fetching schema from remote store.";
     private Client client;
-    private Schema schema;
 
     public ProxyStore() {
         super(false);
@@ -99,9 +100,8 @@ public class ProxyStore extends Store {
             throws StoreException {
         setProperties(properties);
         client = createClient();
-        schema = fetchSchema();
 
-        super.initialise(graphId, schema, getProperties());
+        super.initialise(graphId, new Schema(), getProperties());
         checkDelegateStoreStatus();
     }
 
@@ -158,10 +158,38 @@ public class ProxyStore extends Store {
         return newTraits;
     }
 
-    protected Schema fetchSchema() throws StoreException {
-        final URL url = getProperties().getGafferUrl("graph/config/schema");
-        final ResponseDeserialiser<Schema> responseDeserialiser = getResponseDeserialiserFor(new TypeReferenceStoreImpl.Schema());
-        return doGet(url, responseDeserialiser, null);
+    protected Schema fetchSchema(final boolean getCompactSchema) throws OperationException {
+        final GetSchema.Builder getSchema = new GetSchema.Builder();
+        getSchema.compact(getCompactSchema);
+        return executeOpChainViaUrl(new OperationChain<>(getSchema.build()), new Context());
+    }
+
+    /**
+     * Get original {@link Schema} from the remote Store.
+     *
+     * @return original {@link Schema}
+     */
+    @Override
+    public Schema getOriginalSchema() {
+        try {
+            return fetchSchema(false);
+        } catch (final OperationException e) {
+            throw new GafferRuntimeException(ERROR_FETCHING_SCHEMA_FROM_REMOTE_STORE, e);
+        }
+    }
+
+    /**
+     * Get {@link Schema} from the remote Store.
+     *
+     * @return optimised compact {@link Schema}
+     */
+    @Override
+    public Schema getSchema() {
+        try {
+            return fetchSchema(true);
+        } catch (final OperationException e) {
+            throw new GafferRuntimeException(ERROR_FETCHING_SCHEMA_FROM_REMOTE_STORE, e);
+        }
     }
 
     @Override
diff --git a/store-implementation/proxy-store/src/test/java/uk/gov/gchq/gaffer/proxystore/integration/ProxyStoreBasicIT.java b/store-implementation/proxy-store/src/test/java/uk/gov/gchq/gaffer/proxystore/integration/ProxyStoreBasicIT.java
index 65eeb756cc..8f0455825f 100644
--- a/store-implementation/proxy-store/src/test/java/uk/gov/gchq/gaffer/proxystore/integration/ProxyStoreBasicIT.java
+++ b/store-implementation/proxy-store/src/test/java/uk/gov/gchq/gaffer/proxystore/integration/ProxyStoreBasicIT.java
@@ -50,7 +50,11 @@ import uk.gov.gchq.gaffer.proxystore.ProxyStore;
 import uk.gov.gchq.gaffer.proxystore.SingleUseMapProxyStore;
 import uk.gov.gchq.gaffer.rest.RestApiTestClient;
 import uk.gov.gchq.gaffer.rest.service.v2.RestApiV2TestClient;
+import uk.gov.gchq.gaffer.store.Store;
 import uk.gov.gchq.gaffer.store.StoreTrait;
+import uk.gov.gchq.gaffer.store.operation.GetSchema;
+import uk.gov.gchq.gaffer.store.schema.Schema;
+import uk.gov.gchq.gaffer.store.schema.SchemaOptimiser;
 import uk.gov.gchq.gaffer.user.User;
 
 import java.io.File;
@@ -98,6 +102,7 @@ public class ProxyStoreBasicIT {
                     .build()
     };
 
+    private Store store;
     private Graph graph;
 
     @BeforeAll
@@ -116,13 +121,14 @@ public class ProxyStoreBasicIT {
         CLIENT.reinitialiseGraph(testFolder, StreamUtil.SCHEMA, "map-store.properties");
 
         // setup ProxyStore
+        store = new ProxyStore.Builder()
+                .graphId("graph1")
+                .host("localhost")
+                .port(8080)
+                .contextRoot("rest/v2")
+                .build();
         graph = new Graph.Builder()
-                .store(new ProxyStore.Builder()
-                        .graphId("graph1")
-                        .host("localhost")
-                        .port(8080)
-                        .contextRoot("rest/v2")
-                        .build())
+                .store(store)
                 .build();
     }
 
@@ -237,4 +243,36 @@ public class ProxyStoreBasicIT {
                 .build();
         graph.execute(add, USER);
     }
+
+    @Test
+    public void shouldGetOriginalSchemaUsingMethodsAndOperation() throws OperationException {
+        // Given
+        Schema storeSchema = Schema.fromJson(StreamUtil.openStream(this.getClass(), StreamUtil.SCHEMA));
+
+        // When - Get
+        final Schema returnedSchemaFromGraphMethod = graph.getSchema(); // Indirectly runs getOriginalSchema
+        final Schema returnedSchemaFromStoreMethod = store.getOriginalSchema();
+        final Schema returnedSchemaFromOperation = graph.execute(new GetSchema(), USER);
+
+        // Then
+        assertThat(returnedSchemaFromGraphMethod).isEqualTo(storeSchema);
+        assertThat(returnedSchemaFromStoreMethod).isEqualTo(storeSchema);
+        assertThat(returnedSchemaFromOperation).isEqualTo(storeSchema);
+    }
+
+    @Test
+    public void shouldGetInternalOptimisedSchemaUsingMethodAndOperation() throws OperationException {
+        // Given
+        Schema storeSchema = Schema.fromJson(StreamUtil.openStream(this.getClass(), StreamUtil.SCHEMA));
+        Schema optimisedStoreSchema = new SchemaOptimiser().optimise(storeSchema, true);
+
+        // When - Get
+        final Schema returnedSchemaFromMethod = store.getSchema();
+        GetSchema getCompactSchema = new GetSchema.Builder().compact(true).build();
+        final Schema returnedSchemaFromOperation = graph.execute(getCompactSchema, USER);
+
+        // Then
+        assertThat(returnedSchemaFromMethod).isEqualTo(optimisedStoreSchema);
+        assertThat(returnedSchemaFromOperation).isEqualTo(optimisedStoreSchema);
+    }
 }