[spring-extensions] branch main updated: IDP-1652 - Redesign handling of lists of descriptors

Scott Cantor cantor.2 at osu.edu
Tue Aug 18 15:29:24 UTC 2020


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

scantor pushed a commit to branch main
in repository spring-extensions.

View the commit online:
http://git.shibboleth.net/view/?p=spring-extensions.git;a=commit;h=502227bebf371a45b89af4c299c8b10a8e7bef9b

The following commit(s) were added to refs/heads/main by this push:
       new  502227b   IDP-1652 - Redesign handling of lists of descriptors
502227b is described below

commit 502227bebf371a45b89af4c299c8b10a8e7bef9b
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Aug 18 11:29:16 2020 -0400

    IDP-1652 - Redesign handling of lists of descriptors
    
    https://issues.shibboleth.net/jira/browse/IDP-1652
    
    Utility class to merge static lists and Autowired objects.
---
 .../spring/util/IdentifiedComponentManager.java    | 102 +++++++++++++
 .../util/IdentifiedComponentManagerTest.java       | 167 +++++++++++++++++++++
 .../net/shibboleth/ext/spring/util/combined.xml    |  28 ++++
 .../net/shibboleth/ext/spring/util/freeOnly.xml    |  26 ++++
 .../net/shibboleth/ext/spring/util/overlap.xml     |  29 ++++
 .../net/shibboleth/ext/spring/util/staticOnly.xml  |  27 ++++
 6 files changed, 379 insertions(+)

diff --git a/src/main/java/net/shibboleth/ext/spring/util/IdentifiedComponentManager.java b/src/main/java/net/shibboleth/ext/spring/util/IdentifiedComponentManager.java
new file mode 100644
index 0000000..08a89a1
--- /dev/null
+++ b/src/main/java/net/shibboleth/ext/spring/util/IdentifiedComponentManager.java
@@ -0,0 +1,102 @@
+/*
+ * 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.ext.spring.util;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.component.IdentifiedComponent;
+
+/**
+ * Class used for auto-wiring free-standing identified objects along with explicitly declared
+ * bean collections.
+ * 
+ * <p>This class marries old-style "explicit" list-based configuration of a collection of
+ * objects with annotation-driven discovery of objects of the same type.</p>
+ * 
+ * <p>Specializations of this class are expected to fix the type and add an Autowired
+ * constructor to receive the free-standing objects.</p>
+ * 
+ * @param <T> descriptor type
+ */
+public class IdentifiedComponentManager<T extends IdentifiedComponent> {
+
+    /** Class logger. */
+    @Nonnull private Logger log = LoggerFactory.getLogger(IdentifiedComponentManager.class);
+    
+    /** Underlying collection. */
+    @Nonnull @NonnullElements private Collection<T> components;
+    
+    /**
+     * Auto-wiring point for free-standing objects.
+     * 
+     * @param freeObjects free-standing objects
+     */
+    public IdentifiedComponentManager(@Nullable @NonnullElements final Collection<T> freeObjects) {
+        if (freeObjects != null) {
+            components = List.copyOf(freeObjects);
+        } else {
+            components = Collections.emptyList();
+        }
+    }
+    
+    /**
+     * Sets additional non-autowired components to merge in.
+     * 
+     * <p>For now, this set is prepended to any auto-wired objects and any auto-wired objects
+     * are excluded if they have the same identifier as an explicitly injected object.</p>
+     * 
+     * @param additionalObjects additional objects
+     */
+    public void setComponents(@Nullable @NonnullElements final Collection<T> additionalObjects) {
+        if (additionalObjects != null) {
+            final Collection<T> holder = new LinkedHashSet<>(additionalObjects);
+            holder.addAll(
+                    components.stream()
+                        .filter(obj -> {
+                            if (holder.contains(obj)) {
+                                log.info("Replacing auto-wired component: {}", obj.getId());
+                                return false;
+                            }
+                            return true;
+                        })
+                        .collect(Collectors.toUnmodifiableList()));
+            components = List.copyOf(holder);
+        }
+    }
+    
+    /**
+     * Gets the final collection of merged components.
+     * 
+     * @return merged components
+     */
+    @Nonnull @NonnullElements public Collection<T> getComponents() {
+        return components;
+    }
+    
+}
\ No newline at end of file
diff --git a/src/test/java/net/shibboleth/ext/spring/util/IdentifiedComponentManagerTest.java b/src/test/java/net/shibboleth/ext/spring/util/IdentifiedComponentManagerTest.java
new file mode 100644
index 0000000..dbb9690
--- /dev/null
+++ b/src/test/java/net/shibboleth/ext/spring/util/IdentifiedComponentManagerTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.ext.spring.util;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import javax.annotation.Nonnull;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.GenericApplicationContext;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.component.AbstractIdentifiableInitializableComponent;
+
+/**
+ * Test for {@link IdentifiedComponentManager}.
+ */
+ at SuppressWarnings("javadoc")
+public class IdentifiedComponentManagerTest {
+
+    @Test public void testCombining() {
+        final ApplicationContext context = getContext("net/shibboleth/ext/spring/util/combined.xml");
+        
+        final MockComponentManager manager = context.getBean(MockComponentManager.class);
+        Assert.assertNotNull(manager);
+        Assert.assertEquals(manager.getComponents().size(), 3);
+        
+        Iterator<MockComponent> i = manager.getComponents().iterator();
+        Assert.assertEquals(i.next().getId(), "One");
+        Assert.assertEquals(i.next().getId(), "Two");
+        Assert.assertEquals(i.next().getId(), "Three");
+
+        i = manager.getComponents().iterator();
+        Assert.assertEquals(i.next().getData(), "Foo1");
+        Assert.assertEquals(i.next().getData(), "Foo2");
+        Assert.assertEquals(i.next().getData(), "Foo3");
+    }
+
+    @Test public void testOverlap() {
+        final ApplicationContext context = getContext("net/shibboleth/ext/spring/util/overlap.xml");
+        
+        final MockComponentManager manager = context.getBean(MockComponentManager.class);
+        Assert.assertNotNull(manager);
+        Assert.assertEquals(manager.getComponents().size(), 3);
+        
+        Iterator<MockComponent> i = manager.getComponents().iterator();
+        Assert.assertEquals(i.next().getId(), "One");
+        Assert.assertEquals(i.next().getId(), "Three");
+        Assert.assertEquals(i.next().getId(), "Two");
+
+        i = manager.getComponents().iterator();
+        Assert.assertEquals(i.next().getData(), "Foo1");
+        Assert.assertEquals(i.next().getData(), "Foo3");
+        Assert.assertEquals(i.next().getData(), "Foo2");
+    }
+
+    @Test public void testStaticOnly() {
+        final ApplicationContext context = getContext("net/shibboleth/ext/spring/util/staticOnly.xml");
+        
+        final MockComponentManager manager = context.getBean(MockComponentManager.class);
+        Assert.assertNotNull(manager);
+        Assert.assertEquals(manager.getComponents().size(), 3);
+        
+        Iterator<MockComponent> i = manager.getComponents().iterator();
+        Assert.assertEquals(i.next().getId(), "One");
+        Assert.assertEquals(i.next().getId(), "Two");
+        Assert.assertEquals(i.next().getId(), "Three");
+
+        i = manager.getComponents().iterator();
+        Assert.assertEquals(i.next().getData(), "Foo1");
+        Assert.assertEquals(i.next().getData(), "Foo2");
+        Assert.assertEquals(i.next().getData(), "Foo3");
+    }
+
+    @Test public void testFreeOnly() {
+        final ApplicationContext context = getContext("net/shibboleth/ext/spring/util/freeOnly.xml");
+        
+        final MockComponentManager manager = context.getBean(MockComponentManager.class);
+        Assert.assertNotNull(manager);
+        Assert.assertEquals(manager.getComponents().size(), 1);
+        
+        Iterator<MockComponent> i = manager.getComponents().iterator();
+        Assert.assertEquals(i.next().getId(), "Three");
+
+        i = manager.getComponents().iterator();
+        Assert.assertEquals(i.next().getData(), "Foo3");
+    }
+
+    private ApplicationContext getContext(final String config) {
+        final GenericApplicationContext context = new GenericApplicationContext();
+        final XmlBeanDefinitionReader beanDefinitionReader = new SchemaTypeAwareXMLBeanDefinitionReader(context);
+
+        beanDefinitionReader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD);
+        beanDefinitionReader.loadBeanDefinitions(config);
+        context.refresh();
+     
+        return context;
+    }
+
+    public static class MockComponent extends AbstractIdentifiableInitializableComponent {
+
+        private final String data;
+        
+        public MockComponent(final String s) {
+            data = s;
+        }
+        
+        public String getData() {
+            return data;
+        }
+        
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            return getId().hashCode();
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean equals(final Object obj) {
+            if (obj == null) {
+                return false;
+            }
+
+            if (obj == this) {
+                return true;
+            }
+
+            if (obj instanceof MockComponent) {
+                return getId().equals(((MockComponent) obj).getId());
+            }
+
+            return false;
+        }
+    }
+    
+    public static class MockComponentManager extends IdentifiedComponentManager<MockComponent> {
+        /**
+         * Constructor.
+         *
+         * @param freeObjects
+         */
+        @Autowired
+        public MockComponentManager(@Nonnull @NonnullElements final Collection<MockComponent> freeObjects) {
+            super(freeObjects);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/src/test/resources/net/shibboleth/ext/spring/util/combined.xml b/src/test/resources/net/shibboleth/ext/spring/util/combined.xml
new file mode 100644
index 0000000..d182b33
--- /dev/null
+++ b/src/test/resources/net/shibboleth/ext/spring/util/combined.xml
@@ -0,0 +1,28 @@
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:p="http://www.springframework.org/schema/p"
+       xmlns:c="http://www.springframework.org/schema/c"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+                           
+       default-init-method="initialize"
+       default-destroy-method="destroy">
+
+    <bean class="net.shibboleth.ext.spring.config.IdentifiableBeanPostProcessor" />
+
+    <context:annotation-config />
+
+    <util:list id="StaticList">
+        <bean id="One" class="net.shibboleth.ext.spring.util.IdentifiedComponentManagerTest.MockComponent" c:_0="Foo1" />
+        <bean id="Two" class="net.shibboleth.ext.spring.util.IdentifiedComponentManagerTest.MockComponent" c:_0="Foo2" />
+    </util:list>
+    
+    <bean id="Three" class="net.shibboleth.ext.spring.util.IdentifiedComponentManagerTest.MockComponent" c:_0="Foo3" />
+    
+    <bean class="net.shibboleth.ext.spring.util.IdentifiedComponentManagerTest.MockComponentManager"
+        p:components-ref="StaticList" />
+
+</beans>
\ No newline at end of file
diff --git a/src/test/resources/net/shibboleth/ext/spring/util/freeOnly.xml b/src/test/resources/net/shibboleth/ext/spring/util/freeOnly.xml
new file mode 100644
index 0000000..fc3c104
--- /dev/null
+++ b/src/test/resources/net/shibboleth/ext/spring/util/freeOnly.xml
@@ -0,0 +1,26 @@
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:p="http://www.springframework.org/schema/p"
+       xmlns:c="http://www.springframework.org/schema/c"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+                           
+       default-init-method="initialize"
+       default-destroy-method="destroy">
+
+    <bean class="net.shibboleth.ext.spring.config.IdentifiableBeanPostProcessor" />
+
+    <context:annotation-config />
+
+    <util:list id="StaticList">
+    </util:list>
+    
+    <bean id="Three" class="net.shibboleth.ext.spring.util.IdentifiedComponentManagerTest.MockComponent" c:_0="Foo3" />
+    
+    <bean class="net.shibboleth.ext.spring.util.IdentifiedComponentManagerTest.MockComponentManager"
+        p:components-ref="StaticList" />
+
+</beans>
\ No newline at end of file
diff --git a/src/test/resources/net/shibboleth/ext/spring/util/overlap.xml b/src/test/resources/net/shibboleth/ext/spring/util/overlap.xml
new file mode 100644
index 0000000..ae95f9d
--- /dev/null
+++ b/src/test/resources/net/shibboleth/ext/spring/util/overlap.xml
@@ -0,0 +1,29 @@
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:p="http://www.springframework.org/schema/p"
+       xmlns:c="http://www.springframework.org/schema/c"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+                           
+       default-init-method="initialize"
+       default-destroy-method="destroy">
+
+    <bean class="net.shibboleth.ext.spring.config.IdentifiableBeanPostProcessor" />
+
+    <context:annotation-config />
+
+    <util:list id="StaticList">
+        <bean id="One" class="net.shibboleth.ext.spring.util.IdentifiedComponentManagerTest.MockComponent" c:_0="Foo1" />
+        <bean id="Three" class="net.shibboleth.ext.spring.util.IdentifiedComponentManagerTest.MockComponent" c:_0="Foo3" />
+        <bean id="Two" class="net.shibboleth.ext.spring.util.IdentifiedComponentManagerTest.MockComponent" c:_0="Foo2" />
+    </util:list>
+    
+    <bean p:id="Three" class="net.shibboleth.ext.spring.util.IdentifiedComponentManagerTest.MockComponent" c:_0="Foo4" />
+    
+    <bean class="net.shibboleth.ext.spring.util.IdentifiedComponentManagerTest.MockComponentManager"
+        p:components-ref="StaticList" />
+
+</beans>
\ No newline at end of file
diff --git a/src/test/resources/net/shibboleth/ext/spring/util/staticOnly.xml b/src/test/resources/net/shibboleth/ext/spring/util/staticOnly.xml
new file mode 100644
index 0000000..8ca3167
--- /dev/null
+++ b/src/test/resources/net/shibboleth/ext/spring/util/staticOnly.xml
@@ -0,0 +1,27 @@
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:p="http://www.springframework.org/schema/p"
+       xmlns:c="http://www.springframework.org/schema/c"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+                           
+       default-init-method="initialize"
+       default-destroy-method="destroy">
+
+    <bean class="net.shibboleth.ext.spring.config.IdentifiableBeanPostProcessor" />
+
+    <context:annotation-config />
+
+    <util:list id="StaticList">
+        <bean id="One" class="net.shibboleth.ext.spring.util.IdentifiedComponentManagerTest.MockComponent" c:_0="Foo1" />
+        <bean id="Two" class="net.shibboleth.ext.spring.util.IdentifiedComponentManagerTest.MockComponent" c:_0="Foo2" />
+        <bean id="Three" class="net.shibboleth.ext.spring.util.IdentifiedComponentManagerTest.MockComponent" c:_0="Foo3" />
+    </util:list>
+    
+    <bean class="net.shibboleth.ext.spring.util.IdentifiedComponentManagerTest.MockComponentManager"
+        p:components-ref="StaticList" />
+
+</beans>
\ No newline at end of file

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


More information about the commits mailing list