[java-metadata-aggregator] branch main updated: MDA-295 - PipelineDemultiplexerStage API should avoid use of Pair

Ian Young ian at iay.org.uk
Thu Jul 27 10:29:47 UTC 2023


This is an automated email from the git hooks/post-receive script.

iay pushed a commit to branch main
in repository java-metadata-aggregator.

View the commit online:
http://git.shibboleth.net/view/?p=java-metadata-aggregator.git;a=commit;h=4eafaff01687f4aaef7b22db6e7e388c84e12585

The following commit(s) were added to refs/heads/main by this push:
     new 4eafaff  MDA-295 - PipelineDemultiplexerStage API should avoid use of Pair
4eafaff is described below

commit 4eafaff01687f4aaef7b22db6e7e388c84e12585
Author: Ian Young <ian at iay.org.uk>
AuthorDate: Thu Jul 27 11:29:44 2023 +0100

    MDA-295 - PipelineDemultiplexerStage API should avoid use of Pair
    
    https://shibboleth.atlassian.net/browse/MDA-295
---
 .../metadata/pipeline/PipelineAndStrategy.java     | 45 +++++++++++++
 .../pipeline/PipelineDemultiplexerStage.java       | 78 +++++++++++++++++-----
 .../resources/net/shibboleth/metadata/beans.xml    |  3 +
 .../pipeline/PipelineDemultiplexerStageTest.java   | 55 +++++++++++++--
 4 files changed, 158 insertions(+), 23 deletions(-)

diff --git a/mda-framework/src/main/java/net/shibboleth/metadata/pipeline/PipelineAndStrategy.java b/mda-framework/src/main/java/net/shibboleth/metadata/pipeline/PipelineAndStrategy.java
new file mode 100644
index 0000000..ae170d9
--- /dev/null
+++ b/mda-framework/src/main/java/net/shibboleth/metadata/pipeline/PipelineAndStrategy.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.shibboleth.metadata.pipeline;
+
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.metadata.Item;
+import net.shibboleth.shared.logic.Constraint;
+
+/**
+ * Representation of a {@link Pipeline} and the {@link Predicate} to be used as a strategy to select
+ * items sent to that pipeline.
+ *
+ * @param pipeline a {@link Pipeline} to which items will be sent
+ * @param strategy a {@link Predicate} used to determine which items will be sent to the pipeline
+ * @param <T> type of items processed by the pipeline
+ *
+ * @since 0.10.0
+ */
+public record PipelineAndStrategy<T>(@Nonnull Pipeline<T> pipeline, @Nonnull Predicate<Item<T>> strategy) {
+
+    /**
+     * Constructor.
+     */
+    public PipelineAndStrategy {
+        Constraint.isNotNull(pipeline, "Pipeline can not be null");
+        Constraint.isNotNull(strategy, "strategy can not be null");
+    }
+}
diff --git a/mda-framework/src/main/java/net/shibboleth/metadata/pipeline/PipelineDemultiplexerStage.java b/mda-framework/src/main/java/net/shibboleth/metadata/pipeline/PipelineDemultiplexerStage.java
index 9c85aed..0e1196c 100644
--- a/mda-framework/src/main/java/net/shibboleth/metadata/pipeline/PipelineDemultiplexerStage.java
+++ b/mda-framework/src/main/java/net/shibboleth/metadata/pipeline/PipelineDemultiplexerStage.java
@@ -45,7 +45,8 @@ import net.shibboleth.shared.primitive.DeprecationSupport;
 import net.shibboleth.shared.primitive.DeprecationSupport.ObjectType;
 
 /**
- * A stage which, given an item collection and a list of {@link Pipeline} and {@link Predicate} pairs, sends the
+ * A stage which, given an item collection and a list of {@link PipelineAndStrategy} objects each
+ * representing a {@link Pipeline}s and associated selection strategy {@link Predicate}, sends the
  * collection of item copies selected by the predicate to the associated pipeline.
  *
  * <p>
@@ -57,7 +58,7 @@ import net.shibboleth.shared.primitive.DeprecationSupport.ObjectType;
  * <p>
  * This stage requires the following properties be set prior to initialization:
  * <ul>
- * <li><code>PipelineAndSelectionStrategies</code></li>
+ * <li><code>pipelinesAndStrategies</code></li>
  * </ul>
  * 
  * <p>
@@ -97,7 +98,7 @@ public class PipelineDemultiplexerStage<T> extends AbstractStage<T> {
 
     /** The pipelines through which items are sent and the selection strategy used for that pipeline. */
     @Nonnull @NonnullElements @Unmodifiable @GuardedBy("this")
-    private List<Pair<Pipeline<T>, Predicate<Item<T>>>> pipelineAndStrategies = CollectionSupport.emptyList();
+    private List<PipelineAndStrategy<T>> pipelinesAndStrategies = CollectionSupport.emptyList();
 
     /**
      * Gets the executor used to run the selected and non-selected item pipelines.
@@ -193,27 +194,73 @@ public class PipelineDemultiplexerStage<T> extends AbstractStage<T> {
      * Gets the pipeline and item selection strategies used to demultiplex item collections within this stage.
      * 
      * @return pipeline and item selection strategies used to demultiplex item collections within this stage
+     * @deprecated
      */
+    @Deprecated(since="0.10.0", forRemoval=true)
     @Nonnull @NonnullElements @Unmodifiable public final synchronized List<Pair<Pipeline<T>, Predicate<Item<T>>>>
             getPipelineAndSelectionStrategies() {
-        return pipelineAndStrategies;
+
+        DeprecationSupport.warnOnce(ObjectType.METHOD, "getPipelineAndSelectionStrategies",
+                "PipelineDemultiplexerStage", "getPipelinesAndStrategies");
+
+        final List<Pair<Pipeline<T>, Predicate<Item<T>>>> pas = new ArrayList<>();
+        for (final var entry : pipelinesAndStrategies) {
+            pas.add(new Pair<>(entry.pipeline(), entry.strategy()));
+        }
+        return pas;
     }
 
     /**
      * Sets the pipeline and item selection strategies used to demultiplex item collections within this stage.
      * 
      * @param passes pipeline and item selection strategies used to demultiplex item collections within this stage
+     * @deprecated
      */
+    @Deprecated(since="0.10.0", forRemoval=true)
     public synchronized void setPipelineAndSelectionStrategies(
             @Nonnull @NonnullElements @Unmodifiable final List<Pair<Pipeline<T>, Predicate<Item<T>>>> passes) {
         checkSetterPreconditions();
 
+        DeprecationSupport.warnOnce(ObjectType.METHOD, "setPipelineAndSelectionStrategies",
+                "PipelineDemultiplexerStage", "setPipelinesAndStrategies");
+
+        final List<PipelineAndStrategy<T>> pas = new ArrayList<>();
         for (final Pair<Pipeline<T>, Predicate<Item<T>>> pass : passes) {
-            Constraint.isNotNull(pass.getFirst(), "Pipeline can not be null");
-            Constraint.isNotNull(pass.getSecond(), "Predicate can not be null");
+            final @Nonnull var pipeline = Constraint.isNotNull(pass.getFirst(), "Pipeline can not be null");
+            final @Nonnull var strategy = Constraint.isNotNull(pass.getSecond(), "strategy can not be null");
+            pas.add(new PipelineAndStrategy<T>(pipeline, strategy));
+        }
+        
+        pipelinesAndStrategies = CollectionSupport.copyToList(pas);
+    }
+
+    /**
+     * Gets the pipelines and item selection strategies used to demultiplex item collections within this stage.
+     * 
+     * @return pipeline and item selection strategies used to demultiplex item collections within this stage
+     * @since 0.10.0
+     */
+    public final synchronized @Nonnull @NonnullElements @Unmodifiable List<PipelineAndStrategy<T>>
+            getPipelinesAndStrategies() {
+        return pipelinesAndStrategies;
+    }
+
+    /**
+     * Sets the pipelines and item selection strategies used to demultiplex item collections within this stage.
+     * 
+     * @param passes pipeline and item selection strategies used to demultiplex item collections within this stage
+     * @since 0.10.0
+     */
+    public synchronized void setPipelinesAndStrategies(
+            final @Nonnull @NonnullElements @Unmodifiable List<PipelineAndStrategy<T>> passes) {
+        checkSetterPreconditions();
+
+        for (final var pass : passes) {
+            Constraint.isNotNull(pass.pipeline(), "Pipeline can not be null");
+            Constraint.isNotNull(pass.strategy(), "Predicate can not be null");
         }
 
-        pipelineAndStrategies = CollectionSupport.copyToList(passes);
+        pipelinesAndStrategies = CollectionSupport.copyToList(passes);
     }
 
     @Override
@@ -221,20 +268,18 @@ public class PipelineDemultiplexerStage<T> extends AbstractStage<T> {
             throws StageProcessingException {
         final @Nonnull @NonnullElements List<Future<List<Item<T>>>> pipelineFutures = new ArrayList<>();
 
-        for (final Pair<Pipeline<T>, Predicate<Item<T>>> pipelineAndStrategy : getPipelineAndSelectionStrategies()) {
-            final @Nonnull Pipeline<T> pipeline =
-                    Constraint.isNotNull(pipelineAndStrategy.getFirst(), "pipeline may not be null");
-            final @Nonnull Predicate<Item<T>> selectionStrategy =
-                    Constraint.isNotNull(pipelineAndStrategy.getSecond(), "strategy may not be null");
+        for (final var pipelineAndStrategy : getPipelinesAndStrategies()) {
             final List<Item<T>> selectedItems = getCollectionFactory().get();
             assert selectedItems != null;
 
             for (final Item<T> item : items) {
-                if (selectionStrategy.test(item)) {
+                if (pipelineAndStrategy.strategy().test(item)) {
                     selectedItems.add(item.copy());
                 }
             }
 
+            final var pipeline = pipelineAndStrategy.pipeline();
+            assert pipeline != null;
             final @Nonnull var callable = new PipelineCallable<T>(pipeline, selectedItems);
             final @Nonnull var future = new FutureTask<List<Item<T>>>(callable);
             getExecutor().execute(future);
@@ -253,13 +298,14 @@ public class PipelineDemultiplexerStage<T> extends AbstractStage<T> {
     protected synchronized void doInitialize() throws ComponentInitializationException {
         super.doInitialize();
 
-        if (pipelineAndStrategies.isEmpty()) {
+        if (pipelinesAndStrategies.isEmpty()) {
             throw new ComponentInitializationException(
                     "Pipeline and selection strategy collection can not be empty");
         }
 
-        for (final Pair<Pipeline<T>, Predicate<Item<T>>> pipelineAndStrategy : pipelineAndStrategies) {
-            final var pipeline = Constraint.isNotNull(pipelineAndStrategy.getFirst(), "pipeline may not be null");
+        for (final var pipelineAndStrategy : pipelinesAndStrategies) {
+            final var pipeline = pipelineAndStrategy.pipeline();
+            assert pipeline != null;
             if (!pipeline.isInitialized()) {
                 pipeline.initialize();
             }
diff --git a/mda-framework/src/main/resources/net/shibboleth/metadata/beans.xml b/mda-framework/src/main/resources/net/shibboleth/metadata/beans.xml
index af28e73..322257c 100644
--- a/mda-framework/src/main/resources/net/shibboleth/metadata/beans.xml
+++ b/mda-framework/src/main/resources/net/shibboleth/metadata/beans.xml
@@ -257,6 +257,9 @@
     <bean id="mda.MultiOutputSerializationStage" abstract="true" parent="mda.stage_parent"
         class="net.shibboleth.metadata.pipeline.MultiOutputSerializationStage"/>
 
+    <bean id="mda.PipelineAndStrategy" abstract="true"
+        class="net.shibboleth.metadata.pipeline.PipelineAndStrategy"/>
+
     <bean id="mda.PipelineDemultiplexerStage" abstract="true" parent="mda.stage_parent"
         class="net.shibboleth.metadata.pipeline.PipelineDemultiplexerStage"/>
 
diff --git a/mda-framework/src/test/java/net/shibboleth/metadata/pipeline/PipelineDemultiplexerStageTest.java b/mda-framework/src/test/java/net/shibboleth/metadata/pipeline/PipelineDemultiplexerStageTest.java
index aaf41b6..571e5d1 100644
--- a/mda-framework/src/test/java/net/shibboleth/metadata/pipeline/PipelineDemultiplexerStageTest.java
+++ b/mda-framework/src/test/java/net/shibboleth/metadata/pipeline/PipelineDemultiplexerStageTest.java
@@ -23,6 +23,8 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.function.Predicate;
 
+import javax.annotation.Nonnull;
+
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -65,12 +67,51 @@ public class PipelineDemultiplexerStageTest {
         Assert.assertEquals(stage.getExecutor(), executor);
     }
 
+    // Test deprecated property setter and getter. The internal representation is in
+    // terms of the new record type, and the code is converting on the way in and back out.
+    // Lets make sure that is, at least plausibly, working.
+    @SuppressWarnings("removal")
     @Test public void testPipelineAndSelectionStrategies() {
         PipelineDemultiplexerStage<Object> stage = new PipelineDemultiplexerStage<>();
 
+        // Test with an empty list. It should trivially compare equal to the generated empty list
         final List<Pair<Pipeline<Object>, Predicate<Item<Object>>>> pass = new ArrayList<>();
         stage.setPipelineAndSelectionStrategies(pass);
         Assert.assertEquals(stage.getPipelineAndSelectionStrategies(), pass);
+
+        // A little trickier: a singleton with a couple of empty pipelines and always-boolean strategy
+        // The implementation will reconstruct the original List, although
+        // it will not be identical it should compare equal with what we put in.
+        final Predicate<Item<Object>> truthy = x -> true;
+        final Predicate<Item<Object>> falsey = x -> false;
+        final List<Pair<Pipeline<Object>, Predicate<Item<Object>>>> pass2 = CollectionSupport.listOf(
+                new Pair<>(new SimplePipeline<Object>(), truthy),
+                new Pair<>(new SimplePipeline<Object>(), falsey)
+                );
+        stage.setPipelineAndSelectionStrategies(pass2);
+        Assert.assertEquals(stage.getPipelineAndSelectionStrategies(), pass2);
+    }
+
+    @Test public void testPipelinesAndStrategies() {
+        PipelineDemultiplexerStage<Object> stage = new PipelineDemultiplexerStage<>();
+
+        // Test with an empty list. It should trivially compare equal to the generated empty list
+        final List<PipelineAndStrategy<Object>> pass = new ArrayList<>();
+        stage.setPipelinesAndStrategies(pass);
+        Assert.assertEquals(stage.getPipelinesAndStrategies(), pass);
+
+        // A little trickier: a singleton with a couple of empty pipelines and always-boolean strategy
+        // The implementation will reconstruct the original List, although
+        // it will not be identical it should compare equal with what we put in.
+        final Predicate<Item<Object>> truthy = x -> true;
+        final Predicate<Item<Object>> falsey = x -> false;
+        final @Nonnull List<PipelineAndStrategy<Object>> pass2 = CollectionSupport.listOf(
+                new PipelineAndStrategy<>(new SimplePipeline<Object>(), truthy),
+                new PipelineAndStrategy<>(new SimplePipeline<Object>(), falsey)
+                );
+        System.out.println("..." + pass2.get(0).getClass().getCanonicalName());
+        stage.setPipelinesAndStrategies(pass2);
+        Assert.assertEquals(stage.getPipelinesAndStrategies(), pass2);
     }
 
     @Test public void testWaitingForPipelines() {
@@ -88,8 +129,8 @@ public class PipelineDemultiplexerStageTest {
 
         stage = new PipelineDemultiplexerStage<>();
         stage.setId("test");
-        stage.setPipelineAndSelectionStrategies(CollectionSupport.listOf(new Pair<Pipeline<String>, Predicate<Item<String>>>(pipeline,
-                x -> true)));
+        stage.setPipelinesAndStrategies(CollectionSupport.listOf(
+                new PipelineAndStrategy<>(pipeline, x -> true)));
         stage.initialize();
         Assert.assertNotNull(stage.getCollectionFactory());
         Assert.assertNotNull(stage.getExecutor());
@@ -118,8 +159,8 @@ public class PipelineDemultiplexerStageTest {
         PipelineDemultiplexerStage<String> stage = new PipelineDemultiplexerStage<>();
         stage.setId("test");
         stage.setWaitingForPipelines(true);
-        stage.setPipelineAndSelectionStrategies(CollectionSupport.listOf(new Pair<Pipeline<String>, Predicate<Item<String>>>(pipeline,
-                x -> true)));
+        stage.setPipelinesAndStrategies(CollectionSupport.listOf(
+                new PipelineAndStrategy<>(pipeline, x -> true)));
         stage.initialize();
 
         stage.execute(items);
@@ -127,7 +168,7 @@ public class PipelineDemultiplexerStageTest {
         Assert.assertEquals(countStage.getInvocationCount(), 1);
         stage.destroy();
     }
-    
+
     @Test public void testThrow() throws Exception {
         final SimplePipeline<String> pipeline = new SimplePipeline<>();
         pipeline.setId("selectedPipeline");
@@ -142,8 +183,8 @@ public class PipelineDemultiplexerStageTest {
         PipelineDemultiplexerStage<String> stage = new PipelineDemultiplexerStage<>();
         stage.setId("test");
         stage.setWaitingForPipelines(true);
-        stage.setPipelineAndSelectionStrategies(CollectionSupport.listOf(new Pair<Pipeline<String>, Predicate<Item<String>>>(pipeline,
-                x -> true)));
+        stage.setPipelinesAndStrategies(CollectionSupport.listOf(
+                new PipelineAndStrategy<>(pipeline, x -> true)));
         stage.initialize();
 
         try {

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list