diff --git a/.github/workflows/continuous-integration-legacy.yaml b/.github/workflows/continuous-integration-legacy.yaml index 23e7915e1ca..a52fb2d62bf 100644 --- a/.github/workflows/continuous-integration-legacy.yaml +++ b/.github/workflows/continuous-integration-legacy.yaml @@ -24,7 +24,7 @@ jobs: - name: Accumulo values: :accumulo-store,:accumulo-rest - name: Federated-And-Map - values: :integration-test,:federated-store,:map-store,:map-rest + values: :integration-test,:federated-store,:map-store,:map-rest,:simple-federated-store - name: REST values: :rest-api,:common-rest,:spring-rest,:core-rest,:store-implementation,:proxy-store - name: Examples diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index b454c1a0e6e..c5ef87ff746 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -94,7 +94,7 @@ jobs: - name: Accumulo values: :accumulo-store,:accumulo-rest - name: Federated-And-Map - values: :integration-test,:federated-store,:map-store,:map-rest + values: :integration-test,:federated-store,:map-store,:map-rest,:simple-federated-store - name: REST values: :rest-api,:common-rest,:spring-rest,:core-rest,:store-implementation,:proxy-store - name: Examples diff --git a/core/common-util/src/main/java/uk/gov/gchq/gaffer/commonutil/OneOrMore.java b/core/common-util/src/main/java/uk/gov/gchq/gaffer/commonutil/OneOrMore.java index cce539bc1f0..0176408e4ad 100644 --- a/core/common-util/src/main/java/uk/gov/gchq/gaffer/commonutil/OneOrMore.java +++ b/core/common-util/src/main/java/uk/gov/gchq/gaffer/commonutil/OneOrMore.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -117,14 +117,10 @@ public void removeAnyItem() { } public int size() { - if (null == collection) { - if (null != singleItem) { - return 1; - } - return 0; + if (collection != null) { + return collection.size(); } - - return collection.size(); + return (singleItem != null) ? 1 : 0; } public boolean isEmpty() { diff --git a/core/common-util/src/main/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/ElementVisibility.java b/core/common-util/src/main/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/ElementVisibility.java index b954604dbea..809e1ca4b3b 100644 --- a/core/common-util/src/main/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/ElementVisibility.java +++ b/core/common-util/src/main/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/ElementVisibility.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,6 +39,11 @@ public class ElementVisibility { EMPTY_NODE = new ElementVisibility.Node(ElementVisibility.NodeType.EMPTY, 0); } + public ElementVisibility(final Object expression) { + this.node = null; + this.validate(convert(expression)); + } + public ElementVisibility(final String expression) { this(expression.getBytes(UTF_8)); } @@ -48,6 +53,10 @@ public ElementVisibility(final byte[] expression) { this.validate(expression); } + private byte[] convert(final Object expression) { + return expression.toString().getBytes(UTF_8); + } + public byte[] getExpression() { return this.expression; } diff --git a/core/common-util/src/main/java/uk/gov/gchq/gaffer/commonutil/iterable/LimitedInMemorySortedIterable.java b/core/common-util/src/main/java/uk/gov/gchq/gaffer/commonutil/iterable/LimitedInMemorySortedIterable.java index 48e54eff07e..8668b09e002 100644 --- a/core/common-util/src/main/java/uk/gov/gchq/gaffer/commonutil/iterable/LimitedInMemorySortedIterable.java +++ b/core/common-util/src/main/java/uk/gov/gchq/gaffer/commonutil/iterable/LimitedInMemorySortedIterable.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -86,20 +86,28 @@ public boolean add(final E e) { boolean result = false; final OneOrMore values = backingMap.get(e); - // Skip the item if we are deduplicating and the item already exists + // Skip the item if we are deduplicating and the item already exists. boolean skipItem = (deduplicate && nonNull(values) && values.contains(e)); if (!skipItem) { if (nonNull(limit) && size >= limit) { // Check the item against the last item. final Map.Entry> last = backingMap.lastEntry(); + // Checks if the last items key is greater than e if (0 < comparator.compare(last.getKey(), e)) { + // Checks if the items value contains a collection or a single item if (1 < last.getValue().size()) { + // Items value contains a collection. + // Remove item from collection. last.getValue().removeAnyItem(); } else { + // Items value contains a single item. + // Remove item from backingMap. backingMap.remove(last.getKey()); } size--; + // e is bigger than the lastEntry. } else { + // Skip adding the item. skipItem = true; } } diff --git a/core/common-util/src/main/java/uk/gov/gchq/gaffer/commonutil/otel/OtelUtil.java b/core/common-util/src/main/java/uk/gov/gchq/gaffer/commonutil/otel/OtelUtil.java index 6d33b65647d..7cf3e93ab11 100644 --- a/core/common-util/src/main/java/uk/gov/gchq/gaffer/commonutil/otel/OtelUtil.java +++ b/core/common-util/src/main/java/uk/gov/gchq/gaffer/commonutil/otel/OtelUtil.java @@ -21,6 +21,12 @@ public final class OtelUtil { + public static final String USER_ATTRIBUTE = "enduser.id"; + public static final String JOB_ID_ATTRIBUTE = "gaffer.jobId"; + public static final String GRAPH_ID_ATTRIBUTE = "gaffer.graphId"; + public static final String VIEW_ATTRIBUTE = "gaffer.view"; + public static final String GREMLIN_QUERY_ATTRIBUTE = "gaffer.gremlin.query"; + private static boolean openTelemetryActive = false; private OtelUtil() { diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/OneOrMoreTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/OneOrMoreTest.java index c2a73896a78..d6e49ef708b 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/OneOrMoreTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/OneOrMoreTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,6 @@ import java.util.stream.IntStream; import static org.assertj.core.api.Assertions.assertThat; - public class OneOrMoreTest { @Test @@ -72,6 +71,32 @@ public void shouldRemoveLastItemInList() { .containsExactly(1, 2); } + @Test + void testSizeWithNonNullCollection() { + final boolean deduplicate = true; + final OneOrMore collection = new OneOrMore<>(deduplicate, 1); + collection.add(2); + collection.add(3); + + assertThat(collection).hasSize(3); + } + + @Test + void testSizeWithSingleItem() { + final boolean deduplicate = true; + final OneOrMore collection = new OneOrMore<>(deduplicate, 1); + + assertThat(collection).hasSize(1); + } + + @Test + void testSizeWithNullCollectionAndSingleItem() { + final boolean deduplicate = true; + final OneOrMore collection = new OneOrMore<>(deduplicate, null); + + assertThat(collection).isEmpty(); + } + @Test public void shouldAddItemsWithoutDeduplicate() { // Given diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/ElementVisibilityTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/ElementVisibilityTest.java index 40422e88ea0..a05d99c953d 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/ElementVisibilityTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/elementvisibilityutil/ElementVisibilityTest.java @@ -31,6 +31,19 @@ class ElementVisibilityTest { + @Test + void testIntegerTypeIsAccepted() { + final ElementVisibility ev = new ElementVisibility(1); + assertThat(ev).hasToString("[1]"); + } + + @Test + void testCustomObjectIsAccepted() { + RandomObject randomObject = new RandomObject("Hello", 1); + final ElementVisibility ev = new ElementVisibility(randomObject); + assertThat(ev).hasToString("[hello]"); + } + @Test void testEmptyStringIsValid() { final ElementVisibility a = new ElementVisibility(new byte[0]); @@ -188,4 +201,19 @@ private void assertNode(final ElementVisibility.Node node, final ElementVisibili } ); } + + class RandomObject { + private String randomString; + private Integer randomInteger; + + RandomObject(String randomString, Integer randomInteger) { + this.randomString = randomString; + this.randomInteger = randomInteger; + } + + @Override + public String toString() { + return "hello"; + } + } } diff --git a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/LimitedInMemorySortedIterableTest.java b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/LimitedInMemorySortedIterableTest.java index a5cd7b2c670..d53b42165f1 100644 --- a/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/LimitedInMemorySortedIterableTest.java +++ b/core/common-util/src/test/java/uk/gov/gchq/gaffer/commonutil/iterable/LimitedInMemorySortedIterableTest.java @@ -90,6 +90,18 @@ void shouldLimitAndNotDeduplicateEntries() { assertThat(list).containsExactly(1, 1, 2, 2); } + @Test + void shouldInsertNewItemAndRemoveOldItemWhenlimitIsReachedAndNewItemIsLessThanLastEntry() { + final LimitedInMemorySortedIterable list = new LimitedInMemorySortedIterable(Comparator.naturalOrder(), 3, false); + + list.add(3); + list.add(2); + list.add(3); + list.add(2); + + assertThat(list).hasSize(3).containsExactly(2, 2, 3); + } + @Test void shouldAddAll() { final LimitedInMemorySortedIterable itr = new LimitedInMemorySortedIterable(Comparator.naturalOrder(), 100); diff --git a/core/graph/src/main/java/uk/gov/gchq/gaffer/graph/Graph.java b/core/graph/src/main/java/uk/gov/gchq/gaffer/graph/Graph.java index 34fa107db63..02d616b425a 100644 --- a/core/graph/src/main/java/uk/gov/gchq/gaffer/graph/Graph.java +++ b/core/graph/src/main/java/uk/gov/gchq/gaffer/graph/Graph.java @@ -321,9 +321,9 @@ private GraphResult _execute(final StoreExecuter storeExecuter, final Span span = OtelUtil.startSpan( this.getClass().getName(), "Graph Request: " + clonedOpChain.toOverviewString()); - span.setAttribute("gaffer.graphId", getGraphId()); - span.setAttribute("gaffer.jobId", clonedContext.getJobId()); - span.setAttribute("gaffer.user", clonedContext.getUser().getUserId()); + span.setAttribute(OtelUtil.GRAPH_ID_ATTRIBUTE, getGraphId()); + span.setAttribute(OtelUtil.JOB_ID_ATTRIBUTE, clonedContext.getJobId()); + span.setAttribute(OtelUtil.USER_ATTRIBUTE, clonedContext.getUser().getUserId()); O result = null; // Sets the span to current so parent child spans are auto linked @@ -520,6 +520,10 @@ public GraphLibrary getGraphLibrary() { return store.getCaches(); } + public String getCreatedTime() { + return store.getCreatedTime(); + } + @FunctionalInterface private interface StoreExecuter { O execute(final OperationChain operation, final Context context) throws OperationException; diff --git a/core/graph/src/main/java/uk/gov/gchq/gaffer/graph/hook/NamedOperationResolver.java b/core/graph/src/main/java/uk/gov/gchq/gaffer/graph/hook/NamedOperationResolver.java index 0c8a98f9741..9eec1359a3c 100644 --- a/core/graph/src/main/java/uk/gov/gchq/gaffer/graph/hook/NamedOperationResolver.java +++ b/core/graph/src/main/java/uk/gov/gchq/gaffer/graph/hook/NamedOperationResolver.java @@ -128,6 +128,7 @@ private Collection resolveNamedOperations(final Operation operation, .getOperationChain(namedOperation.getParameters()); // Update the operation inputs and add operation chain to the updated list OperationHandlerUtil.updateOperationInput(namedOperationChain, namedOperation.getInput()); + namedOperationChain.setOptions(namedOperation.getOptions()); // Run again to resolve any nested operations in the chain before adding namedOperationChain.updateOperations(resolveNamedOperations(namedOperationChain, user, depth + 1)); diff --git a/core/graph/src/test/java/uk/gov/gchq/gaffer/graph/GraphTest.java b/core/graph/src/test/java/uk/gov/gchq/gaffer/graph/GraphTest.java index 1b2cb76f6a7..ae42ec9d588 100644 --- a/core/graph/src/test/java/uk/gov/gchq/gaffer/graph/GraphTest.java +++ b/core/graph/src/test/java/uk/gov/gchq/gaffer/graph/GraphTest.java @@ -81,6 +81,7 @@ import uk.gov.gchq.gaffer.store.TestTypes; import uk.gov.gchq.gaffer.store.library.GraphLibrary; import uk.gov.gchq.gaffer.store.library.HashMapGraphLibrary; +import uk.gov.gchq.gaffer.store.operation.DeleteAllData; 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; @@ -104,6 +105,8 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -117,6 +120,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.within; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -2687,6 +2691,31 @@ public void shouldNotExpandGlobalEdgesWhereNotPresentInSchema(@Mock final Store assertNotNull(mergedView.getGlobalEdges().get(0).getPostAggregationFilter()); } + @Test + void shouldGetGraphCreatedTime() { + // Given + final Store store = new TestStoreImpl(); + final Schema schema = new Schema.Builder().build(); + Graph graph = new Graph.Builder() + .config(new GraphConfig.Builder() + .graphId(GRAPH_ID) + .build()) + .storeProperties(StreamUtil.storeProps(getClass())) + .store(store) + .addSchema(schema) + .build(); + + // When + String graphCreatedTime = graph.getCreatedTime(); + + // Then + assertThat(graphCreatedTime) + .isNotNull() + .isInstanceOf(String.class); + assertThat(LocalDateTime.parse(graphCreatedTime)) + .isInstanceOf(LocalDateTime.class) + .isCloseTo(LocalDateTime.now(), within(20, ChronoUnit.SECONDS)); + } public static class TestStoreImpl extends Store { @Override @@ -2719,6 +2748,11 @@ protected OperationHandler getDeleteElementsHandler() return null; } + @Override + protected OperationHandler getDeleteAllDataHandler() { + return null; + } + @Override protected OutputOperationHandler> getGetTraitsHandler() { return new GetTraitsHandler(new HashSet<>(0)); diff --git a/core/graph/src/test/java/uk/gov/gchq/gaffer/integration/store/TestStore.java b/core/graph/src/test/java/uk/gov/gchq/gaffer/integration/store/TestStore.java index e98525a75d9..7a3180ee22d 100644 --- a/core/graph/src/test/java/uk/gov/gchq/gaffer/integration/store/TestStore.java +++ b/core/graph/src/test/java/uk/gov/gchq/gaffer/integration/store/TestStore.java @@ -32,6 +32,7 @@ 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.DeleteAllData; 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; @@ -89,6 +90,11 @@ protected OperationHandler getDeleteElementsHandler() return null; } + @Override + protected OperationHandler getDeleteAllDataHandler() { + return null; + } + @Override protected OutputOperationHandler> getGetTraitsHandler() { return mock(GetTraitsHandler.class); diff --git a/core/operation/src/main/java/uk/gov/gchq/gaffer/operation/data/EdgeSeed.java b/core/operation/src/main/java/uk/gov/gchq/gaffer/operation/data/EdgeSeed.java index 01d46c8fa89..e4a798fa8bf 100644 --- a/core/operation/src/main/java/uk/gov/gchq/gaffer/operation/data/EdgeSeed.java +++ b/core/operation/src/main/java/uk/gov/gchq/gaffer/operation/data/EdgeSeed.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 Crown Copyright + * Copyright 2016-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/core/operation/src/main/java/uk/gov/gchq/gaffer/operation/impl/get/GetGraphCreatedTime.java b/core/operation/src/main/java/uk/gov/gchq/gaffer/operation/impl/get/GetGraphCreatedTime.java new file mode 100644 index 00000000000..5806ea06ccb --- /dev/null +++ b/core/operation/src/main/java/uk/gov/gchq/gaffer/operation/impl/get/GetGraphCreatedTime.java @@ -0,0 +1,64 @@ +/* + * Copyright 2024 Crown Copyright + * + * Licensed 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 uk.gov.gchq.gaffer.operation.impl.get; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.core.type.TypeReference; +import org.apache.commons.lang3.exception.CloneFailedException; + +import uk.gov.gchq.gaffer.operation.Operation; +import uk.gov.gchq.gaffer.operation.io.Output; +import uk.gov.gchq.koryphe.Since; +import uk.gov.gchq.koryphe.Summary; + +import java.util.Map; + +@Since("2.3.1") +@Summary("Operation to retrieve Graph created date") +@JsonPropertyOrder(alphabetic = true) +public class GetGraphCreatedTime implements Output> { + private Map options; + + @Override + public Operation shallowClone() throws CloneFailedException { + return new Builder() + .options(options) + .build(); + } + + @Override + public Map getOptions() { + return options; + } + + @Override + public void setOptions(final Map options) { + this.options = options; + } + + @Override + public TypeReference> getOutputTypeReference() { + return new TypeReference>() { }; + + } + + public static class Builder extends Operation.BaseBuilder implements Output.Builder, Builder> { + public Builder() { + super(new GetGraphCreatedTime()); + } + + } +} diff --git a/core/operation/src/main/java/uk/gov/gchq/gaffer/operation/serialisation/TypeReferenceImpl.java b/core/operation/src/main/java/uk/gov/gchq/gaffer/operation/serialisation/TypeReferenceImpl.java index a5028f67503..b0b8562f2cb 100644 --- a/core/operation/src/main/java/uk/gov/gchq/gaffer/operation/serialisation/TypeReferenceImpl.java +++ b/core/operation/src/main/java/uk/gov/gchq/gaffer/operation/serialisation/TypeReferenceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2023 Crown Copyright + * Copyright 2016-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -95,6 +95,8 @@ public static class Map extends TypeReference { public static class MapStringObject extends TypeReference> { } + public static class MapStringString extends TypeReference> { + } public static class MapStringSet extends TypeReference>> { } diff --git a/core/operation/src/test/java/uk/gov/gchq/gaffer/operation/impl/get/GetGraphCreatedTimeTest.java b/core/operation/src/test/java/uk/gov/gchq/gaffer/operation/impl/get/GetGraphCreatedTimeTest.java new file mode 100644 index 00000000000..6bb5cb5bcb4 --- /dev/null +++ b/core/operation/src/test/java/uk/gov/gchq/gaffer/operation/impl/get/GetGraphCreatedTimeTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2024 Crown Copyright + * + * Licensed 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 uk.gov.gchq.gaffer.operation.impl.get; + +import org.junit.jupiter.api.Test; + +import uk.gov.gchq.gaffer.operation.Operation; +import uk.gov.gchq.gaffer.operation.OperationTest; + +import static org.assertj.core.api.Assertions.assertThat; + +public class GetGraphCreatedTimeTest extends OperationTest { + + @Test + public void builderShouldCreatePopulatedOperation() { + final GetGraphCreatedTime op = new GetGraphCreatedTime(); + + assertThat(op).isInstanceOf(GetGraphCreatedTime.class); + } + + protected GetGraphCreatedTime getTestObject() { + return new GetGraphCreatedTime(); + } + + @Test + public void shouldShallowCloneOperation() { + // Given + final GetGraphCreatedTime getGraphCreatedTime = new GetGraphCreatedTime(); + + // When + final Operation clone = getGraphCreatedTime.shallowClone(); + + // Then + assertThat(clone).isNotSameAs(getGraphCreatedTime); + } +} diff --git a/core/store/src/main/java/uk/gov/gchq/gaffer/store/Store.java b/core/store/src/main/java/uk/gov/gchq/gaffer/store/Store.java index a48fb54480f..d153548bacd 100644 --- a/core/store/src/main/java/uk/gov/gchq/gaffer/store/Store.java +++ b/core/store/src/main/java/uk/gov/gchq/gaffer/store/Store.java @@ -79,6 +79,7 @@ import uk.gov.gchq.gaffer.operation.impl.get.GetAdjacentIds; import uk.gov.gchq.gaffer.operation.impl.get.GetAllElements; import uk.gov.gchq.gaffer.operation.impl.get.GetElements; +import uk.gov.gchq.gaffer.operation.impl.get.GetGraphCreatedTime; import uk.gov.gchq.gaffer.operation.impl.job.CancelScheduledJob; import uk.gov.gchq.gaffer.operation.impl.job.GetAllJobDetails; import uk.gov.gchq.gaffer.operation.impl.job.GetJobDetails; @@ -98,6 +99,7 @@ import uk.gov.gchq.gaffer.serialisation.Serialiser; import uk.gov.gchq.gaffer.store.library.GraphLibrary; import uk.gov.gchq.gaffer.store.library.NoGraphLibrary; +import uk.gov.gchq.gaffer.store.operation.DeleteAllData; import uk.gov.gchq.gaffer.store.operation.GetSchema; import uk.gov.gchq.gaffer.store.operation.GetTraits; import uk.gov.gchq.gaffer.store.operation.HasTrait; @@ -113,6 +115,7 @@ import uk.gov.gchq.gaffer.store.operation.handler.CountHandler; import uk.gov.gchq.gaffer.store.operation.handler.DiscardOutputHandler; import uk.gov.gchq.gaffer.store.operation.handler.ForEachHandler; +import uk.gov.gchq.gaffer.store.operation.handler.GetGraphCreatedTimeHandler; import uk.gov.gchq.gaffer.store.operation.handler.GetSchemaHandler; import uk.gov.gchq.gaffer.store.operation.handler.GetVariableHandler; import uk.gov.gchq.gaffer.store.operation.handler.GetVariablesHandler; @@ -173,6 +176,7 @@ import uk.gov.gchq.koryphe.ValidationResult; import uk.gov.gchq.koryphe.util.ReflectionUtil; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -212,6 +216,7 @@ public abstract class Store { protected final OperationChainValidator opChainValidator; private final SchemaOptimiser schemaOptimiser; private final Boolean addCoreOpHandlers; + private final LocalDateTime createdTime = LocalDateTime.now(); /** * The schema - contains the type of {@link uk.gov.gchq.gaffer.data.element.Element}s @@ -312,6 +317,14 @@ public void initialise(final String graphId, final Schema schema, final StorePro } } } + /** + * Gets this Store's creation timestamp for {@link GetGraphCreatedTime} operation. + * + * @return the Store's creation timestamp. + */ + public String getCreatedTime() { + return createdTime.toString(); + } private void rescheduleJob(final JobDetail jobDetail) { @@ -896,6 +909,14 @@ public List getOperationChainOptimisers() { */ protected abstract OperationHandler getDeleteElementsHandler(); + /** + * Get this Store's implementation of the handler for {@link uk.gov.gchq.gaffer.operation.DeleteAllData}. + * All Stores must implement this. + * + * @return the implementation of the handler for {@link uk.gov.gchq.gaffer.operation.DeleteAllData} + */ + protected abstract OperationHandler getDeleteAllDataHandler(); + /** * Get this Store's implementation of the handler for {@link uk.gov.gchq.gaffer.store.operation.GetTraits}. * All Stores must implement this. @@ -1017,6 +1038,9 @@ private void addCoreOpHandlers() { // Delete elements addOperationHandler(DeleteElements.class, getDeleteElementsHandler()); + // Delete all data + addOperationHandler(DeleteAllData.class, getDeleteAllDataHandler()); + // Get Elements addOperationHandler(GetElements.class, getGetElementsHandler()); @@ -1097,6 +1121,8 @@ private void addCoreOpHandlers() { addOperationHandler(ToSingletonList.class, new ToSingletonListHandler()); addOperationHandler(Reduce.class, new ReduceHandler()); addOperationHandler(Join.class, new JoinHandler()); + addOperationHandler(GetGraphCreatedTime.class, new GetGraphCreatedTimeHandler()); + // Context variables addOperationHandler(SetVariable.class, new SetVariableHandler()); diff --git a/core/store/src/main/java/uk/gov/gchq/gaffer/store/library/GraphLibrary.java b/core/store/src/main/java/uk/gov/gchq/gaffer/store/library/GraphLibrary.java index b58a463b5a4..6ed865adf4f 100644 --- a/core/store/src/main/java/uk/gov/gchq/gaffer/store/library/GraphLibrary.java +++ b/core/store/src/main/java/uk/gov/gchq/gaffer/store/library/GraphLibrary.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 Crown Copyright + * Copyright 2017-2024 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ * A {@code GraphLibrary} stores a graphId and its related Schema and StoreProperties. */ public abstract class GraphLibrary { - protected static final Pattern ID_ALLOWED_CHARACTERS = Pattern.compile("[a-zA-Z0-9_]*"); + protected static final Pattern ID_ALLOWED_CHARACTERS = Pattern.compile("\\w*"); public static final String A_GRAPH_LIBRARY_CAN_T_BE_ADDED_WITH_A_NULL_S_GRAPH_ID_S = "A GraphLibrary can't be added with a null %s, graphId: %s"; public abstract void initialise(final String path); diff --git a/core/store/src/main/java/uk/gov/gchq/gaffer/store/operation/handler/GetGraphCreatedTimeHandler.java b/core/store/src/main/java/uk/gov/gchq/gaffer/store/operation/handler/GetGraphCreatedTimeHandler.java new file mode 100644 index 00000000000..081cd98aaca --- /dev/null +++ b/core/store/src/main/java/uk/gov/gchq/gaffer/store/operation/handler/GetGraphCreatedTimeHandler.java @@ -0,0 +1,39 @@ +/* + * Copyright 2024 Crown Copyright + * + * Licensed 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 uk.gov.gchq.gaffer.store.operation.handler; + +import uk.gov.gchq.gaffer.operation.OperationException; +import uk.gov.gchq.gaffer.operation.impl.get.GetGraphCreatedTime; +import uk.gov.gchq.gaffer.store.Context; +import uk.gov.gchq.gaffer.store.Store; + +import java.util.HashMap; +import java.util.Map; + +/** + * A {@code GetGraphCreatedTimeHandler} handles {@link GetGraphCreatedTime} operations. + */ + public class GetGraphCreatedTimeHandler implements OperationHandler { + @Override + public Map doOperation(final GetGraphCreatedTime operation, final Context context, final Store store) + throws OperationException { + Map timestamps = new HashMap<>(); + timestamps.put(store.getGraphId(), store.getCreatedTime()); + + return timestamps; + } + } diff --git a/core/store/src/main/java/uk/gov/gchq/gaffer/store/operation/handler/OperationChainHandler.java b/core/store/src/main/java/uk/gov/gchq/gaffer/store/operation/handler/OperationChainHandler.java index ba0cd9bfc48..f866460215e 100644 --- a/core/store/src/main/java/uk/gov/gchq/gaffer/store/operation/handler/OperationChainHandler.java +++ b/core/store/src/main/java/uk/gov/gchq/gaffer/store/operation/handler/OperationChainHandler.java @@ -23,6 +23,7 @@ import uk.gov.gchq.gaffer.operation.Operation; import uk.gov.gchq.gaffer.operation.OperationChain; import uk.gov.gchq.gaffer.operation.OperationException; +import uk.gov.gchq.gaffer.operation.graph.OperationView; import uk.gov.gchq.gaffer.store.Context; import uk.gov.gchq.gaffer.store.Store; import uk.gov.gchq.gaffer.store.operation.OperationChainValidator; @@ -51,7 +52,11 @@ public OUT doOperation(final OperationChain operationChain, final Context c for (final Operation op : preparedOperationChain.getOperations()) { // OpenTelemetry hooks Span span = OtelUtil.startSpan(this.getClass().getName(), op.getClass().getName()); - span.setAttribute("jobId", context.getJobId()); + span.setAttribute(OtelUtil.JOB_ID_ATTRIBUTE, context.getJobId()); + if (op instanceof OperationView && ((OperationView) op).getView() != null) { + span.setAttribute(OtelUtil.VIEW_ATTRIBUTE, ((OperationView) op).getView().toString()); + } + // Sets the span to current so parent child spans are auto linked try (Scope scope = span.makeCurrent()) { updateOperationInput(op, result); diff --git a/core/store/src/test/java/uk/gov/gchq/gaffer/store/StoreTest.java b/core/store/src/test/java/uk/gov/gchq/gaffer/store/StoreTest.java index 2eaafd8c112..c01e7241d8c 100644 --- a/core/store/src/test/java/uk/gov/gchq/gaffer/store/StoreTest.java +++ b/core/store/src/test/java/uk/gov/gchq/gaffer/store/StoreTest.java @@ -92,6 +92,7 @@ import uk.gov.gchq.gaffer.operation.impl.get.GetAdjacentIds; import uk.gov.gchq.gaffer.operation.impl.get.GetAllElements; import uk.gov.gchq.gaffer.operation.impl.get.GetElements; +import uk.gov.gchq.gaffer.operation.impl.get.GetGraphCreatedTime; import uk.gov.gchq.gaffer.operation.impl.job.CancelScheduledJob; import uk.gov.gchq.gaffer.operation.impl.job.GetAllJobDetails; import uk.gov.gchq.gaffer.operation.impl.job.GetJobDetails; @@ -112,6 +113,7 @@ import uk.gov.gchq.gaffer.serialisation.implementation.tostring.StringToStringSerialiser; import uk.gov.gchq.gaffer.store.Store.ScheduledJobRunnable; import uk.gov.gchq.gaffer.store.library.GraphLibrary; +import uk.gov.gchq.gaffer.store.operation.DeleteAllData; import uk.gov.gchq.gaffer.store.operation.GetSchema; import uk.gov.gchq.gaffer.store.operation.GetTraits; import uk.gov.gchq.gaffer.store.operation.HasTrait; @@ -139,6 +141,7 @@ import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; @@ -603,6 +606,7 @@ public void shouldReturnAllSupportedOperationsWhenJobTrackerIsEnabled(@Mock fina ForEach.class, Reduce.class, CancelScheduledJob.class, + GetGraphCreatedTime.class, // Function Filter.class, @@ -711,6 +715,7 @@ public void shouldReturnAllSupportedOperationsWhenJobTrackerIsDisabled(@Mock fin ToSingletonList.class, ForEach.class, Reduce.class, + GetGraphCreatedTime.class, // Function Filter.class, @@ -916,6 +921,19 @@ public void shouldSetAndGetGraphLibrary(@Mock final GraphLibrary graphLibrary) { assertThat(result).isSameAs(graphLibrary); } + @Test + void shouldGetCreatedTime() { + // Given + final Store testStore = new StoreImpl(); + + // When + String storeTime = testStore.getCreatedTime(); + + // Then + assertThat(storeTime).isInstanceOf(String.class); + assertThat(LocalDateTime.parse(storeTime)).isInstanceOf(LocalDateTime.class); + } + private Schema createSchemaMock() { final Schema schema = mock(Schema.class); given(schema.validate()).willReturn(new ValidationResult()); @@ -1175,6 +1193,11 @@ protected OperationHandler getDeleteElementsHandler() return null; } + @Override + protected OperationHandler getDeleteAllDataHandler() { + return null; + } + @Override protected OutputOperationHandler> getGetTraitsHandler() { return new GetTraitsHandler(traits); @@ -1271,6 +1294,11 @@ protected OperationHandler getDeleteElementsHandler() return null; } + @Override + protected OperationHandler getDeleteAllDataHandler() { + return null; + } + @Override protected OutputOperationHandler> getGetTraitsHandler() { return new GetTraitsHandler(traits); @@ -1376,6 +1404,11 @@ protected OperationHandler getDeleteElementsHandler() return null; } + @Override + protected OperationHandler getDeleteAllDataHandler() { + return null; + } + @Override protected OutputOperationHandler> getGetTraitsHandler() { return new GetTraitsHandler(traits); diff --git a/core/store/src/test/java/uk/gov/gchq/gaffer/store/integration/StoreIT.java b/core/store/src/test/java/uk/gov/gchq/gaffer/store/integration/StoreIT.java index c95bb45a202..64f4d663311 100644 --- a/core/store/src/test/java/uk/gov/gchq/gaffer/store/integration/StoreIT.java +++ b/core/store/src/test/java/uk/gov/gchq/gaffer/store/integration/StoreIT.java @@ -36,6 +36,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.operation.DeleteAllData; 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; @@ -148,6 +149,11 @@ protected OperationHandler getDeleteElementsHandler() return null; } + @Override + protected OperationHandler getDeleteAllDataHandler() { + return null; + } + @Override protected OutputOperationHandler> getGetTraitsHandler() { return new GetTraitsHandler(traits); diff --git a/core/store/src/test/java/uk/gov/gchq/gaffer/store/operation/handler/GetGraphCreatedTimeHandlerTest.java b/core/store/src/test/java/uk/gov/gchq/gaffer/store/operation/handler/GetGraphCreatedTimeHandlerTest.java new file mode 100644 index 00000000000..edd264026ec --- /dev/null +++ b/core/store/src/test/java/uk/gov/gchq/gaffer/store/operation/handler/GetGraphCreatedTimeHandlerTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2024 Crown Copyright + * + * Licensed 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 uk.gov.gchq.gaffer.store.operation.handler; + +import org.junit.jupiter.api.Test; +import static org.mockito.Mockito.mock; + +import uk.gov.gchq.gaffer.operation.OperationException; +import uk.gov.gchq.gaffer.operation.impl.get.GetGraphCreatedTime; +import uk.gov.gchq.gaffer.store.Context; +import uk.gov.gchq.gaffer.store.Store; +import uk.gov.gchq.gaffer.user.User; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class GetGraphCreatedTimeHandlerTest { + private final Store store = mock(Store.class); + private final Context context = new Context(new User()); + private final GetGraphCreatedTimeHandler handler = new GetGraphCreatedTimeHandler(); + + @Test + void shouldReturnGraphCreatedTimeMap() throws OperationException { + // Given + GetGraphCreatedTime op = new GetGraphCreatedTime(); + + // When + Map result = handler.doOperation(op, context, store); + + // Then + assertThat(result).isInstanceOf(Map.class); + } +} diff --git a/core/store/src/test/java/uk/gov/gchq/gaffer/store/operation/handler/TestAddToGraphLibraryImpl.java b/core/store/src/test/java/uk/gov/gchq/gaffer/store/operation/handler/TestAddToGraphLibraryImpl.java index 19e17193dd9..1ce44a44781 100644 --- a/core/store/src/test/java/uk/gov/gchq/gaffer/store/operation/handler/TestAddToGraphLibraryImpl.java +++ b/core/store/src/test/java/uk/gov/gchq/gaffer/store/operation/handler/TestAddToGraphLibraryImpl.java @@ -27,6 +27,7 @@ import uk.gov.gchq.gaffer.serialisation.ToBytesSerialiser; import uk.gov.gchq.gaffer.store.Store; import uk.gov.gchq.gaffer.store.StoreTrait; +import uk.gov.gchq.gaffer.store.operation.DeleteAllData; import uk.gov.gchq.gaffer.store.operation.GetTraits; import java.util.HashSet; @@ -57,6 +58,11 @@ protected OperationHandler getAddElementsHandler() { return null; } + @Override + protected OperationHandler getDeleteAllDataHandler() { + return null; + } + @Override protected OutputOperationHandler> getGetTraitsHandler() { return new GetTraitsHandler(new HashSet<>(0)); diff --git a/example/federated-demo/README.md b/example/federated-demo/README.md index 7b8f461a526..9157f56a30f 100644 --- a/example/federated-demo/README.md +++ b/example/federated-demo/README.md @@ -71,8 +71,7 @@ To add a Map graph, execute this operation (or run addMapEdgesGraph.sh): ] } } - } - }, + }, "isPublic": true } ``` diff --git a/library/tinkerpop/pom.xml b/library/tinkerpop/pom.xml index 645ec6d4963..1536f173bc5 100644 --- a/library/tinkerpop/pom.xml +++ b/library/tinkerpop/pom.xml @@ -111,6 +111,12 @@ ${project.parent.version} test + + uk.gov.gchq.gaffer + simple-federated-store + ${project.parent.version} + test + org.apache.tinkerpop diff --git a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraph.java b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraph.java index 89d4af3397d..e416951b825 100755 --- a/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraph.java +++ b/library/tinkerpop/src/main/java/uk/gov/gchq/gaffer/tinkerpop/GafferPopGraph.java @@ -35,6 +35,7 @@ import org.slf4j.LoggerFactory; import uk.gov.gchq.gaffer.data.element.Element; +import uk.gov.gchq.gaffer.data.element.id.EntityId; import uk.gov.gchq.gaffer.data.elementdefinition.view.View; import uk.gov.gchq.gaffer.graph.Graph; import uk.gov.gchq.gaffer.graph.GraphConfig; @@ -51,13 +52,16 @@ import uk.gov.gchq.gaffer.operation.impl.get.GetAllElements; import uk.gov.gchq.gaffer.operation.impl.get.GetElements; import uk.gov.gchq.gaffer.operation.io.Input; +import uk.gov.gchq.gaffer.store.operation.GetSchema; import uk.gov.gchq.gaffer.store.schema.Schema; import uk.gov.gchq.gaffer.tinkerpop.generator.GafferEdgeGenerator; import uk.gov.gchq.gaffer.tinkerpop.generator.GafferEntityGenerator; import uk.gov.gchq.gaffer.tinkerpop.generator.GafferPopElementGenerator; import uk.gov.gchq.gaffer.tinkerpop.process.traversal.strategy.optimisation.GafferPopGraphStepStrategy; import uk.gov.gchq.gaffer.tinkerpop.process.traversal.strategy.optimisation.GafferPopHasStepStrategy; +import uk.gov.gchq.gaffer.tinkerpop.process.traversal.strategy.optimisation.GafferPopVertexStepStrategy; import uk.gov.gchq.gaffer.tinkerpop.process.traversal.util.GafferCustomTypeFactory; +import uk.gov.gchq.gaffer.tinkerpop.process.traversal.util.GafferVertexUtils; import uk.gov.gchq.gaffer.tinkerpop.service.GafferPopNamedOperationServiceFactory; import uk.gov.gchq.gaffer.user.User; import uk.gov.gchq.koryphe.iterable.MappedIterable; @@ -78,6 +82,7 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -178,14 +183,14 @@ public class GafferPopGraph implements org.apache.tinkerpop.gremlin.structure.Gr public static final String OP_OPTIONS = "gaffer.operation.options"; /** - * Configuration key for the max number of elements returned by getAllElements + * Configuration key for the max number of elements returned by a getElements */ - public static final String GET_ALL_ELEMENTS_LIMIT = "gaffer.elements.getalllimit"; + public static final String GET_ELEMENTS_LIMIT = "gaffer.elements.getlimit"; /** - * Default value for the max number of elements returned by getAllElements + * Default value for the max number of elements returned by getElements */ - public static final int DEFAULT_GET_ALL_ELEMENTS_LIMIT = 5000; + public static final int DEFAULT_GET_ELEMENTS_LIMIT = 5000; /** * Configuration key for when to apply HasStep filtering @@ -254,7 +259,7 @@ public enum DefaultIdManager { private final ServiceRegistry serviceRegistry; private static final Logger LOGGER = LoggerFactory.getLogger(GafferPopGraph.class); - private static final String GET_ALL_DEBUG_MSG = "Requested a GetAllElements, results will be truncated to: {}."; + private static final String GET_DEBUG_MSG = "Requested a GetElements, results will be truncated to: {}."; private static final Pattern EDGE_ID_REGEX = Pattern.compile("^\\s*\\[\\s*(?[a-zA-Z0-9|-]*)\\s*(,\\s*(?