[java-metadata-aggregator] 03/03: MDA-182 - refactor Stage implementation class hierarchy

Ian Young ian at iay.org.uk
Thu Jun 29 12:52:54 EDT 2017


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

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

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

commit a86864286c4093716ef50b5e122ebb7fa4e8d5a3
Author: Ian Young <ian at iay.org.uk>
AuthorDate: Thu Jun 29 17:51:18 2017 +0100

    MDA-182 - refactor Stage implementation class hierarchy
    
    Phase 3: reparent stages where possible to simplify implementation.
---
 .../metadata/dom/AbstractDOMTraversalStage.java    | 17 ++---
 .../dom/AbstractNamespacesStrippingStage.java      | 23 ++----
 .../metadata/dom/ElementStrippingStage.java        | 52 +++++++-------
 .../metadata/dom/EmptyContainerStrippingStage.java | 50 ++++++-------
 .../saml/mdattr/EntityAttributeAddingStage.java    | 82 ++++++++++------------
 .../saml/mdattr/EntityAttributeFilteringStage.java | 64 ++++++++---------
 .../RegistrationAuthorityPopulationStage.java      | 67 ++++++++----------
 .../metadata/pipeline/ItemIdTransformStage.java    |  9 +--
 .../metadata/pipeline/ItemMetadataAddingStage.java |  6 +-
 .../pipeline/MultiOutputSerializationStage.java    | 18 ++---
 10 files changed, 169 insertions(+), 219 deletions(-)

diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/AbstractDOMTraversalStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/AbstractDOMTraversalStage.java
index 34537f9..2d8b628 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/AbstractDOMTraversalStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/AbstractDOMTraversalStage.java
@@ -17,7 +17,6 @@
 
 package net.shibboleth.metadata.dom;
 
-import java.util.Collection;
 import java.util.List;
 
 import javax.annotation.Nonnull;
@@ -30,7 +29,7 @@ import net.shibboleth.metadata.ErrorStatus;
 import net.shibboleth.metadata.Item;
 import net.shibboleth.metadata.ItemMetadata;
 import net.shibboleth.metadata.dom.saml.SAMLMetadataSupport;
-import net.shibboleth.metadata.pipeline.AbstractStage;
+import net.shibboleth.metadata.pipeline.AbstractIteratingStage;
 import net.shibboleth.metadata.pipeline.StageProcessingException;
 import net.shibboleth.utilities.java.support.collection.ClassToInstanceMultiMap;
 import net.shibboleth.utilities.java.support.xml.ElementSupport;
@@ -39,7 +38,7 @@ import net.shibboleth.utilities.java.support.xml.ElementSupport;
  * An abstract DOM traversal class using the template method pattern.
  */
 @ThreadSafe
-public abstract class AbstractDOMTraversalStage extends AbstractStage<Element> {
+public abstract class AbstractDOMTraversalStage extends AbstractIteratingStage<Element> {
     
     /** Context for a particular traversal. */
     protected class TraversalContext {
@@ -118,14 +117,12 @@ public abstract class AbstractDOMTraversalStage extends AbstractStage<Element> {
             visit(element, context);
         }
     }
-    
+
     @Override
-    protected void doExecute(final Collection<Item<Element>> itemCollection) throws StageProcessingException {
-        for (final Item<Element> item : itemCollection) {
-            final Element docElement = item.unwrap();
-            final TraversalContext context = new TraversalContext(item);
-            traverse(docElement, context);
-        }
+    protected void doExecute(final Item<Element> item) throws StageProcessingException {
+        final Element docElement = item.unwrap();
+        final TraversalContext context = new TraversalContext(item);
+        traverse(docElement, context);
     }
 
     /**
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/AbstractNamespacesStrippingStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/AbstractNamespacesStrippingStage.java
index d5baf3a..91e6e91 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/AbstractNamespacesStrippingStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/AbstractNamespacesStrippingStage.java
@@ -18,7 +18,6 @@
 package net.shibboleth.metadata.dom;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 
 import javax.annotation.Nonnull;
@@ -36,9 +35,7 @@ import org.w3c.dom.NodeList;
 import net.shibboleth.metadata.ErrorStatus;
 import net.shibboleth.metadata.Item;
 import net.shibboleth.metadata.ItemMetadata;
-import net.shibboleth.metadata.pipeline.AbstractStage;
-import net.shibboleth.metadata.pipeline.StageProcessingException;
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.metadata.pipeline.AbstractIteratingStage;
 import net.shibboleth.utilities.java.support.collection.ClassToInstanceMultiMap;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
@@ -52,7 +49,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
  * Attributes without an explicit namespace prefix will never be removed.
  */
 @ThreadSafe
-public abstract class AbstractNamespacesStrippingStage extends AbstractStage<Element> {
+public abstract class AbstractNamespacesStrippingStage extends AbstractIteratingStage<Element> {
 
     /** Class logger. */
     private final Logger log = LoggerFactory.getLogger(AbstractNamespacesStrippingStage.class);
@@ -65,12 +62,8 @@ public abstract class AbstractNamespacesStrippingStage extends AbstractStage<Ele
      */
     protected abstract boolean removingNamespace(final String namespace);
 
-    /**
-     * Processes the given {@link Item}.
-     * 
-     * @param item {@link Item} to process.
-     */
-    private void processItem(@Nonnull final Item<Element> item) {
+    @Override
+    protected void doExecute(@Nonnull final Item<Element> item) {
         final Element element = Constraint.isNotNull(item, "Item can not be null").unwrap();
     
         /*
@@ -178,12 +171,4 @@ public abstract class AbstractNamespacesStrippingStage extends AbstractStage<Ele
         processAttributes(element);
     }
 
-    @Override
-    protected void doExecute(@Nonnull @NonnullElements final Collection<Item<Element>> items)
-            throws StageProcessingException {
-        for (final Item<Element> item : items) {
-            processItem(item);
-        }
-    }
-
 }
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/ElementStrippingStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/ElementStrippingStage.java
index ce8b93a..a586f43 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/ElementStrippingStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/ElementStrippingStage.java
@@ -18,31 +18,29 @@
 package net.shibboleth.metadata.dom;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.ThreadSafe;
 
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
 import net.shibboleth.metadata.Item;
-import net.shibboleth.metadata.pipeline.AbstractStage;
+import net.shibboleth.metadata.pipeline.AbstractIteratingStage;
 import net.shibboleth.metadata.pipeline.StageProcessingException;
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-
 /**
  * A stage which removes all instances of the specified element from DOM metadata.
  */
 @ThreadSafe
-public class ElementStrippingStage extends AbstractStage<Element> {
+public class ElementStrippingStage extends AbstractIteratingStage<Element> {
 
     /** Namespace of the element to strip. */
     private String elementNamespace;
@@ -94,27 +92,25 @@ public class ElementStrippingStage extends AbstractStage<Element> {
                 "target element name can not be null or empty");
     }
 
-    /** {@inheritDoc} */
-    @Override protected void doExecute(@Nonnull @NonnullElements final Collection<Item<Element>> items)
+    @Override
+    protected void doExecute(@Nonnull final Item<Element> item)
             throws StageProcessingException {
-        for (final Item<Element> item : items) {
-            final Element docElement = item.unwrap();
-
-            // List all the matching descendant elements in this document in document order
-            // Note that this list will never include the document element itself
-            final NodeList nodeList = docElement.getElementsByTagNameNS(elementNamespace, elementName);
-
-            // Copy these into a list, because a NodeList can change length at any time
-            final int nNodes = nodeList.getLength();
-            final List<Element> elements = new ArrayList<>(nNodes);
-            for (int eIndex = 0; eIndex < nNodes; eIndex++) {
-                elements.add((Element) nodeList.item(eIndex));
-            }
-            
-            // Remove the elements from the document
-            for (final Element element : elements) {
-                element.getParentNode().removeChild(element);
-            }
+        final Element docElement = item.unwrap();
+
+        // List all the matching descendant elements in this document in document order
+        // Note that this list will never include the document element itself
+        final NodeList nodeList = docElement.getElementsByTagNameNS(elementNamespace, elementName);
+
+        // Copy these into a list, because a NodeList can change length at any time
+        final int nNodes = nodeList.getLength();
+        final List<Element> elements = new ArrayList<>(nNodes);
+        for (int eIndex = 0; eIndex < nNodes; eIndex++) {
+            elements.add((Element) nodeList.item(eIndex));
+        }
+
+        // Remove the elements from the document
+        for (final Element element : elements) {
+            element.getParentNode().removeChild(element);
         }
     }
 
@@ -137,4 +133,4 @@ public class ElementStrippingStage extends AbstractStage<Element> {
         }
     }
 
-}
\ No newline at end of file
+}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/EmptyContainerStrippingStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/EmptyContainerStrippingStage.java
index 48fee77..fb8e642 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/EmptyContainerStrippingStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/EmptyContainerStrippingStage.java
@@ -17,16 +17,16 @@
 
 package net.shibboleth.metadata.dom;
 
-import java.util.Collection;
-
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.annotation.concurrent.ThreadSafe;
 
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
 import net.shibboleth.metadata.Item;
-import net.shibboleth.metadata.pipeline.AbstractStage;
-import net.shibboleth.metadata.pipeline.StageProcessingException;
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.metadata.pipeline.AbstractIteratingStage;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
@@ -34,15 +34,11 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 import net.shibboleth.utilities.java.support.xml.ElementSupport;
 
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
 /**
  * A stage which removes all empty instances of the named container element from DOM metadata.
  */
 @ThreadSafe
-public class EmptyContainerStrippingStage extends AbstractStage<Element> {
+public class EmptyContainerStrippingStage extends AbstractIteratingStage<Element> {
 
     /** Namespace of the element to strip. */
     private String elementNamespace;
@@ -101,26 +97,24 @@ public class EmptyContainerStrippingStage extends AbstractStage<Element> {
      * @return true if and only if the Element has child elements.
      */
     private boolean hasChildElements(@Nonnull final Element element) {
-        final Node firstChild = ElementSupport.getFirstChildElement(Constraint.isNotNull(element, "Element can not be null"));
+        final Node firstChild =
+                ElementSupport.getFirstChildElement(Constraint.isNotNull(element, "Element can not be null"));
         return firstChild != null;
     }
-    
-    /** {@inheritDoc} */
-    @Override protected void doExecute(@Nonnull @NonnullElements final Collection<Item<Element>> items)
-            throws StageProcessingException {
-        for (final Item<Element> item : items) {
-            final Element element = item.unwrap();
-            
-            // List all the relevant elements in this document in document order
-            final NodeList extensionList = element.getElementsByTagNameNS(elementNamespace, elementName);
-            
-            // Process in reverse order so that, for example, Extensions inside Extensions are
-            // handled correctly.
-            for (int eIndex = extensionList.getLength()-1; eIndex >= 0; eIndex--) {
-                final Element extensions = (Element) extensionList.item(eIndex);
-                if (!hasChildElements(extensions)) {
-                    extensions.getParentNode().removeChild(extensions);
-                }
+
+    @Override
+    protected void doExecute(@Nonnull final Item<Element> item) {
+        final Element element = item.unwrap();
+
+        // List all the relevant elements in this document in document order
+        final NodeList extensionList = element.getElementsByTagNameNS(elementNamespace, elementName);
+
+        // Process in reverse order so that, for example, Extensions inside Extensions are
+        // handled correctly.
+        for (int eIndex = extensionList.getLength()-1; eIndex >= 0; eIndex--) {
+            final Element extensions = (Element) extensionList.item(eIndex);
+            if (!hasChildElements(extensions)) {
+                extensions.getParentNode().removeChild(extensions);
             }
         }
     }
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/EntityAttributeAddingStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/EntityAttributeAddingStage.java
index efeee3e..f5d6993 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/EntityAttributeAddingStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/EntityAttributeAddingStage.java
@@ -17,11 +17,17 @@
 
 package net.shibboleth.metadata.dom.saml.mdattr;
 
-import java.util.Collection;
 import java.util.List;
 
 import javax.annotation.Nonnull;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Element;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+
 import net.shibboleth.metadata.Item;
 import net.shibboleth.metadata.dom.Container;
 import net.shibboleth.metadata.dom.saml.AttributeElementMaker;
@@ -30,24 +36,16 @@ import net.shibboleth.metadata.dom.saml.AttributeValueElementMaker;
 import net.shibboleth.metadata.dom.saml.AttributeValueElementMatcher;
 import net.shibboleth.metadata.dom.saml.SAMLMetadataSupport;
 import net.shibboleth.metadata.dom.saml.SAMLSupport;
-import net.shibboleth.metadata.pipeline.AbstractStage;
-import net.shibboleth.metadata.pipeline.StageProcessingException;
+import net.shibboleth.metadata.pipeline.AbstractIteratingStage;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Element;
-
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-
 /**
  * A stage which adds entity attribute values to entity definitions.
  */
-public class EntityAttributeAddingStage extends AbstractStage<Element> {
+public class EntityAttributeAddingStage extends AbstractIteratingStage<Element> {
 
     /** Class logger. */
     private final Logger log = LoggerFactory.getLogger(EntityAttributeAddingStage.class);
@@ -202,39 +200,37 @@ public class EntityAttributeAddingStage extends AbstractStage<Element> {
     }
 
     @Override
-    protected void doExecute(@Nonnull final Collection<Item<Element>> itemCollection) throws StageProcessingException {
-        for (final Item<Element> item : itemCollection) {
-            final Element entity = item.unwrap();
-            if (SAMLMetadataSupport.isEntityDescriptor(entity)) {
-                // Start from the entity
-                final Container entityContainer = new Container(entity);
-
-                // Dig down to <Extensions>
-                final Container extensionsContainer =
-                        entityContainer.locateChild(SAMLSupport.EXTENSIONS_MATCHER,
-                                SAMLSupport.EXTENSIONS_MAKER, Container.FIRST_CHILD);
-
-                // Dig down to <EntityAttributes>
-                final Container attributesContainer =
-                        extensionsContainer.locateChild(MDAttrSupport.ENTITY_ATTRIBUTES_MATCHER,
-                                MDAttrSupport.ENTITY_ATTRIBUTES_MAKER,
-                                addingFirstChild ? Container.FIRST_CHILD : Container.LAST_CHILD);
-
-                // Collect all matching <Attribute> containers
-                final List<Container> attributes =
-                        attributesContainer.findChildren(attributeMatcher);
-
-                // If any of the existing attribute values match our value, we're done
-                if (attributeValuePresent(attributes)) {
-                    log.debug("attribute value '{}' already present", attributeValue);
-                    continue;
-                }
-
-                // If not already present, re-locate an <Attribute> and add it in there.
-                final Container attribute =
-                        attributesContainer.locateChild(attributeMatcher, attributeMaker, Container.LAST_CHILD);
-                attribute.addChild(attributeValueMaker, Container.LAST_CHILD);
+    protected void doExecute(@Nonnull final Item<Element> item) {
+        final Element entity = item.unwrap();
+        if (SAMLMetadataSupport.isEntityDescriptor(entity)) {
+            // Start from the entity
+            final Container entityContainer = new Container(entity);
+
+            // Dig down to <Extensions>
+            final Container extensionsContainer =
+                    entityContainer.locateChild(SAMLSupport.EXTENSIONS_MATCHER,
+                            SAMLSupport.EXTENSIONS_MAKER, Container.FIRST_CHILD);
+
+            // Dig down to <EntityAttributes>
+            final Container attributesContainer =
+                    extensionsContainer.locateChild(MDAttrSupport.ENTITY_ATTRIBUTES_MATCHER,
+                            MDAttrSupport.ENTITY_ATTRIBUTES_MAKER,
+                            addingFirstChild ? Container.FIRST_CHILD : Container.LAST_CHILD);
+
+            // Collect all matching <Attribute> containers
+            final List<Container> attributes =
+                    attributesContainer.findChildren(attributeMatcher);
+
+            // If any of the existing attribute values match our value, we're done
+            if (attributeValuePresent(attributes)) {
+                log.debug("attribute value '{}' already present", attributeValue);
+                return;
             }
+
+            // If not already present, re-locate an <Attribute> and add it in there.
+            final Container attribute =
+                    attributesContainer.locateChild(attributeMatcher, attributeMaker, Container.LAST_CHILD);
+            attribute.addChild(attributeValueMaker, Container.LAST_CHILD);
         }
     }
 
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/EntityAttributeFilteringStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/EntityAttributeFilteringStage.java
index 96409a2..3b4c455 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/EntityAttributeFilteringStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/EntityAttributeFilteringStage.java
@@ -17,31 +17,29 @@
 
 package net.shibboleth.metadata.dom.saml.mdattr;
 
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import com.google.common.base.Predicate;
+
 import net.shibboleth.metadata.Item;
 import net.shibboleth.metadata.WarningStatus;
 import net.shibboleth.metadata.dom.saml.SAMLMetadataSupport;
 import net.shibboleth.metadata.dom.saml.SAMLSupport;
 import net.shibboleth.metadata.dom.saml.mdrpi.RegistrationAuthority;
-import net.shibboleth.metadata.pipeline.AbstractStage;
-import net.shibboleth.metadata.pipeline.StageProcessingException;
+import net.shibboleth.metadata.pipeline.AbstractIteratingStage;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.xml.ElementSupport;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import com.google.common.base.Predicate;
-
 /**
  * A stage which filters entity attributes from entity definitions according to a supplied
  * set of rules.
@@ -56,7 +54,7 @@ import com.google.common.base.Predicate;
  * The stage can be operated in a whitelisting mode (the default) or in a blacklisting mode
  * by setting the <code>whitelisting</code> property to <code>false</code>.
  */
-public class EntityAttributeFilteringStage extends AbstractStage<Element> {
+public class EntityAttributeFilteringStage extends AbstractIteratingStage<Element> {
 
     /** Class logger. */
     private final Logger log = LoggerFactory.getLogger(EntityAttributeFilteringStage.class);
@@ -369,30 +367,28 @@ public class EntityAttributeFilteringStage extends AbstractStage<Element> {
             }
         }
     }
-    
+
     @Override
-    protected void doExecute(final Collection<Item<Element>> itemCollection) throws StageProcessingException {
-        for (final Item<Element> item : itemCollection) {
-            final Element entity = item.unwrap();
-            
-            // Establish the item's registrationAuthority, if any
-            final String registrationAuthority = extractRegistrationAuthority(item);
-
-            /*
-             * Process each EntityAttributes container independently. There MUST be only one
-             * such container according to the specification, but we can't count on that being
-             * picked up elsewhere as it isn't a schema constraint.
-             */
-            for (final Element entityAttributes : SAMLMetadataSupport.getDescriptorExtensionList(entity,
-                    MDAttrSupport.ENTITY_ATTRIBUTES_NAME)) {
-                filterEntityAttributes(entityAttributes, registrationAuthority, item);
-                
-                // remove the EntityAttributes container if it is now empty
-                if (ElementSupport.getFirstChildElement(entityAttributes) == null) {
-                    log.debug("removing empty EntityAttributes");
-                    final Node extensions = entityAttributes.getParentNode();
-                    extensions.removeChild(entityAttributes);
-                }
+    protected void doExecute(@Nonnull final Item<Element> item) {
+        final Element entity = item.unwrap();
+
+        // Establish the item's registrationAuthority, if any
+        final String registrationAuthority = extractRegistrationAuthority(item);
+
+        /*
+         * Process each EntityAttributes container independently. There MUST be only one
+         * such container according to the specification, but we can't count on that being
+         * picked up elsewhere as it isn't a schema constraint.
+         */
+        for (final Element entityAttributes : SAMLMetadataSupport.getDescriptorExtensionList(entity,
+                MDAttrSupport.ENTITY_ATTRIBUTES_NAME)) {
+            filterEntityAttributes(entityAttributes, registrationAuthority, item);
+
+            // remove the EntityAttributes container if it is now empty
+            if (ElementSupport.getFirstChildElement(entityAttributes) == null) {
+                log.debug("removing empty EntityAttributes");
+                final Node extensions = entityAttributes.getParentNode();
+                extensions.removeChild(entityAttributes);
             }
         }
     }
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdrpi/RegistrationAuthorityPopulationStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdrpi/RegistrationAuthorityPopulationStage.java
index b111360..d210059 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdrpi/RegistrationAuthorityPopulationStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdrpi/RegistrationAuthorityPopulationStage.java
@@ -17,62 +17,57 @@
 
 package net.shibboleth.metadata.dom.saml.mdrpi;
 
-import java.util.Collection;
-
 import javax.annotation.Nonnull;
 import javax.annotation.concurrent.ThreadSafe;
 
+import org.w3c.dom.Element;
+
+import com.google.common.base.Strings;
+
 import net.shibboleth.metadata.ErrorStatus;
 import net.shibboleth.metadata.Item;
 import net.shibboleth.metadata.ItemMetadata;
 import net.shibboleth.metadata.dom.saml.SAMLMetadataSupport;
-import net.shibboleth.metadata.pipeline.AbstractStage;
+import net.shibboleth.metadata.pipeline.AbstractIteratingStage;
 import net.shibboleth.metadata.pipeline.StageProcessingException;
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.collection.ClassToInstanceMultiMap;
 import net.shibboleth.utilities.java.support.xml.AttributeSupport;
 
-import org.w3c.dom.Element;
-
-import com.google.common.base.Strings;
-
 /**
  * A stage which, for each EntityDescriptor collection element, adds a {@link RegistrationAuthority}, with
  * the entity's registration authority, to the item metadata.
  */
 @ThreadSafe
-public class RegistrationAuthorityPopulationStage extends AbstractStage<Element> {
+public class RegistrationAuthorityPopulationStage extends AbstractIteratingStage<Element> {
 
-    /** {@inheritDoc} */
-    @Override protected void doExecute(@Nonnull @NonnullElements final Collection<Item<Element>> items)
+    @Override
+    protected void doExecute(@Nonnull final Item<Element> item)
             throws StageProcessingException {
 
-        for (final Item<Element> item : items) {
-           final Element entity = item.unwrap();
-           final ClassToInstanceMultiMap<ItemMetadata> metadata = item.getItemMetadata();
-           
-           if (!SAMLMetadataSupport.isEntityDescriptor(entity)) {
-               // all items must be EntityDescriptor elements
-               metadata.put(new ErrorStatus(getId(), "item was not an EntityDescriptor"));
-           } else {
-               // Extract mdrpi:RegistrationInfo if present.
-               final Element regInfo = SAMLMetadataSupport.getDescriptorExtension(entity,
-                       MDRPIMetadataSupport.MDRPI_REGISTRATION_INFO);
-               if (regInfo != null) {
-                   // Extract registrationAuthority
-                   final String attr = AttributeSupport.getAttributeValue(regInfo, null, "registrationAuthority");
-                   if (attr == null) {
-                       final String eid = Strings.nullToEmpty(
-                               AttributeSupport.getAttributeValue(entity, null, "entityID"));
-                       metadata.put(new ErrorStatus(getId(), "RegistrationInfo for " + eid +
-                               " did not have a RegistrationAuthority attribute"));
-                   } else {
-                       metadata.put(new RegistrationAuthority(attr));
-                   }
+       final Element entity = item.unwrap();
+       final ClassToInstanceMultiMap<ItemMetadata> metadata = item.getItemMetadata();
+
+       if (!SAMLMetadataSupport.isEntityDescriptor(entity)) {
+           // all items must be EntityDescriptor elements
+           metadata.put(new ErrorStatus(getId(), "item was not an EntityDescriptor"));
+       } else {
+           // Extract mdrpi:RegistrationInfo if present.
+           final Element regInfo = SAMLMetadataSupport.getDescriptorExtension(entity,
+                   MDRPIMetadataSupport.MDRPI_REGISTRATION_INFO);
+           if (regInfo != null) {
+               // Extract registrationAuthority
+               final String attr = AttributeSupport.getAttributeValue(regInfo, null, "registrationAuthority");
+               if (attr == null) {
+                   final String eid = Strings.nullToEmpty(
+                           AttributeSupport.getAttributeValue(entity, null, "entityID"));
+                   metadata.put(new ErrorStatus(getId(), "RegistrationInfo for " + eid +
+                           " did not have a RegistrationAuthority attribute"));
+               } else {
+                   metadata.put(new RegistrationAuthority(attr));
                }
            }
-           
-        }
+       }
+
     }
-    
+
 }
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemIdTransformStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemIdTransformStage.java
index 9f2fb61..28d218f 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemIdTransformStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemIdTransformStage.java
@@ -41,7 +41,7 @@ import net.shibboleth.utilities.java.support.component.ComponentSupport;
  * @param <T> type of {@link Item} this stage operates upon
  */
 @ThreadSafe
-public class ItemIdTransformStage<T> extends AbstractFilteringStage<T> {
+public class ItemIdTransformStage<T> extends AbstractIteratingStage<T> {
 
     /** Transformers used on IDs. */
     private Collection<Function<String, String>> idTransformers = new LazyList<>();
@@ -67,9 +67,8 @@ public class ItemIdTransformStage<T> extends AbstractFilteringStage<T> {
         CollectionSupport.addIf(idTransformers, transformers, Predicates.notNull());
     }
 
-    /** {@inheritDoc} */
     @Override
-    protected boolean doExecute(@Nonnull final Item<T> item) throws StageProcessingException {
+    protected void doExecute(@Nonnull final Item<T> item) throws StageProcessingException {
         final List<ItemId> ids = item.getItemMetadata().get(ItemId.class);
 
         final List<ItemId> transformedIds = new ArrayList<>();
@@ -80,7 +79,5 @@ public class ItemIdTransformStage<T> extends AbstractFilteringStage<T> {
             }
         }
         item.getItemMetadata().putAll(transformedIds);
-        
-        return true;
     }
-}
\ No newline at end of file
+}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemMetadataAddingStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemMetadataAddingStage.java
index 1245da8..9a20289 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemMetadataAddingStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemMetadataAddingStage.java
@@ -37,7 +37,7 @@ import com.google.common.base.Predicates;
  * @param <T> type of {@link Item} this stage operates upon
  */
 @ThreadSafe
-public class ItemMetadataAddingStage<T> extends AbstractFilteringStage<T> {
+public class ItemMetadataAddingStage<T> extends AbstractIteratingStage<T> {
 
     /** {@link ItemMetadata} objects to add to each {@link Item}'s item metadata. */
     private Collection<ItemMetadata> additionalItemMetadata = new LazyList<>();
@@ -67,10 +67,8 @@ public class ItemMetadataAddingStage<T> extends AbstractFilteringStage<T> {
         CollectionSupport.addIf(additionalItemMetadata, metadata, Predicates.notNull());
     }
 
-    /** {@inheritDoc} */
     @Override
-    protected boolean doExecute(@Nonnull final Item<T> item) throws StageProcessingException {
+    protected void doExecute(@Nonnull final Item<T> item) throws StageProcessingException {
         item.getItemMetadata().putAll(additionalItemMetadata);
-        return true;
     }
 }
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/MultiOutputSerializationStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/MultiOutputSerializationStage.java
index 4ec1e9b..2abafd9 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/MultiOutputSerializationStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/MultiOutputSerializationStage.java
@@ -20,7 +20,6 @@ package net.shibboleth.metadata.pipeline;
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.util.Collection;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -28,7 +27,6 @@ import javax.annotation.concurrent.ThreadSafe;
 
 import net.shibboleth.metadata.Item;
 import net.shibboleth.metadata.ItemSerializer;
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -49,7 +47,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
  * @param <T> type of items upon which this stage operates
  */
 @ThreadSafe
-public class MultiOutputSerializationStage<T> extends AbstractStage<T> {
+public class MultiOutputSerializationStage<T> extends AbstractIteratingStage<T> {
 
     /**
      * Interface implemented by destination objects created by an {@link OutputStrategy}.
@@ -141,15 +139,13 @@ public class MultiOutputSerializationStage<T> extends AbstractStage<T> {
     }
 
     @Override
-    protected void doExecute(@Nonnull @NonnullElements final Collection<Item<T>> itemCollection)
+    protected void doExecute(@Nonnull final Item<T> item)
             throws StageProcessingException {
-        for (final Item<T> item : itemCollection) {
-            try (final Destination destination = outputStrategy.getDestination(item);
-                    final OutputStream stream = destination.getOutputStream()) {
-                serializer.serialize(item, stream);
-            } catch (final IOException e) {
-                throw new StageProcessingException("Error writing to output location", e);
-            }
+        try (final Destination destination = outputStrategy.getDestination(item);
+                final OutputStream stream = destination.getOutputStream()) {
+            serializer.serialize(item, stream);
+        } catch (final IOException e) {
+            throw new StageProcessingException("Error writing to output location", e);
         }
     }
 

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


More information about the commits mailing list