[java-metadata-aggregator] branch master updated: MDA-242 - Review for thread safety
Ian Young
ian at iay.org.uk
Tue Jul 14 16:10:32 UTC 2020
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=8e3d404d9a6a9185da103ae881dc909e69d14851
The following commit(s) were added to refs/heads/master by this push:
new 8e3d404 MDA-242 - Review for thread safety
8e3d404 is described below
commit 8e3d404d9a6a9185da103ae881dc909e69d14851
Author: Ian Young <ian at iay.org.uk>
AuthorDate: Tue Jul 14 17:10:28 2020 +0100
MDA-242 - Review for thread safety
https://issues.shibboleth.net/jira/browse/MDA-242
Second tranche: dom.saml.mdattr, dom.saml.mdrpi, dom.saml.mdui, pipeline, pipeline.impl.
---
.../mdattr/AbstractEntityAttributeMatcher.java | 4 +-
.../dom/saml/mdattr/AbstractExactValueMatcher.java | 13 +-
.../saml/mdattr/AssuranceCertificationMatcher.java | 4 +-
.../saml/mdattr/EntityAttributeAddingStage.java | 142 ++++++++++-----------
.../saml/mdattr/EntityAttributeFilteringStage.java | 32 +++--
.../dom/saml/mdattr/EntityCategoryMatcher.java | 4 +-
.../saml/mdattr/EntityCategorySupportMatcher.java | 4 +-
.../dom/saml/mdattr/MultiPredicateMatcher.java | 35 ++---
.../saml/mdattr/RegistrationAuthorityMatcher.java | 7 +-
.../EntityRegistrationAuthorityFilterStage.java | 47 +++----
...trationAuthorityItemIdentificationStrategy.java | 20 +--
.../dom/saml/mdui/IPHintValidationStage.java | 9 +-
.../AbstractItemMetadataSelectionStage.java | 23 ++--
.../metadata/pipeline/AbstractStage.java | 9 +-
.../pipeline/AtLeastCollectionPredicate.java | 12 +-
.../metadata/pipeline/CompositeStage.java | 7 +-
.../FilesInDirectoryMultiOutputStrategy.java | 35 ++---
.../metadata/pipeline/FutureSupport.java | 7 +-
.../metadata/pipeline/ItemIdTransformStage.java | 7 +-
.../metadata/pipeline/ItemMetadataAddingStage.java | 9 +-
.../metadata/pipeline/ItemMetadataFilterStage.java | 6 +-
.../pipeline/ItemMetadataTerminationStage.java | 6 +-
.../metadata/pipeline/ItemOrderingStage.java | 7 +-
.../metadata/pipeline/ItemOrderingStrategy.java | 6 +
.../pipeline/MultiOutputSerializationStage.java | 12 +-
.../net/shibboleth/metadata/pipeline/Pipeline.java | 4 +
.../metadata/pipeline/PipelineCallable.java | 4 +-
.../pipeline/PipelineDemultiplexerStage.java | 21 +--
.../metadata/pipeline/PipelineMergeStage.java | 22 ++--
.../metadata/pipeline/ScriptletStage.java | 17 ++-
.../metadata/pipeline/SerializationStage.java | 33 ++---
.../metadata/pipeline/SplitMergeStage.java | 51 ++++----
.../net/shibboleth/metadata/pipeline/Stage.java | 4 +-
.../metadata/pipeline/StaticItemSourceStage.java | 5 +-
.../pipeline/StatusMetadataLoggingStage.java | 12 +-
.../pipeline/impl/NoOpItemOrderingStrategy.java | 2 +
36 files changed, 346 insertions(+), 296 deletions(-)
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/AbstractEntityAttributeMatcher.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/AbstractEntityAttributeMatcher.java
index 92f9aff..838107f 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/AbstractEntityAttributeMatcher.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/AbstractEntityAttributeMatcher.java
@@ -21,7 +21,7 @@ import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import javax.annotation.concurrent.ThreadSafe;
+import javax.annotation.concurrent.Immutable;
import net.shibboleth.metadata.dom.saml.mdattr.EntityAttributeFilteringStage.EntityAttributeContext;
@@ -37,7 +37,7 @@ import net.shibboleth.metadata.dom.saml.mdattr.EntityAttributeFilteringStage.Ent
*
* @since 0.9.0
*/
- at ThreadSafe
+ at Immutable
public abstract class AbstractEntityAttributeMatcher implements Predicate<EntityAttributeContext> {
/**
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/AbstractExactValueMatcher.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/AbstractExactValueMatcher.java
index c814330..1a0bfed 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/AbstractExactValueMatcher.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/AbstractExactValueMatcher.java
@@ -19,7 +19,7 @@ package net.shibboleth.metadata.dom.saml.mdattr;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import javax.annotation.concurrent.ThreadSafe;
+import javax.annotation.concurrent.Immutable;
import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -30,17 +30,17 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
*
* @since 0.9.0
*/
- at ThreadSafe
+ at Immutable
public abstract class AbstractExactValueMatcher extends AbstractEntityAttributeMatcher {
/** The attribute value to match. */
- private final String value;
+ @Nonnull private final String value;
/** The attribute <code>Name</code> to match. */
- private final String name;
+ @Nonnull private final String name;
/** The attribute <code>NameFormat</code> to match. */
- private final String nameFormat;
+ @Nonnull private final String nameFormat;
/** Registration authority to match against, or <code>null</code>. */
@Nullable
@@ -84,9 +84,8 @@ public abstract class AbstractExactValueMatcher extends AbstractEntityAttributeM
if (registrationAuthority == null) {
// ignore the context's registration authority value
return true;
- } else {
- return registrationAuthority.equals(inputRegistrationAuthority);
}
+ return registrationAuthority.equals(inputRegistrationAuthority);
}
}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/AssuranceCertificationMatcher.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/AssuranceCertificationMatcher.java
index 7c1e3ab..aeed636 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/AssuranceCertificationMatcher.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/AssuranceCertificationMatcher.java
@@ -19,14 +19,14 @@ package net.shibboleth.metadata.dom.saml.mdattr;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import javax.annotation.concurrent.ThreadSafe;
+import javax.annotation.concurrent.Immutable;
/**
* An entity attribute matcher which matches a given assurance certification value.
*
* @since 0.10.0
*/
- at ThreadSafe
+ at Immutable
public class AssuranceCertificationMatcher extends AbstractExactValueMatcher {
/** Attribute Name value for assurance certifications. */
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 8701af1..24e846a 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,13 @@
package net.shibboleth.metadata.dom.saml.mdattr;
+import java.util.Collection;
import java.util.List;
-import java.util.function.Function;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
+import javax.annotation.concurrent.ThreadSafe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,8 +37,8 @@ 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.AbstractIteratingStage;
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.metadata.pipeline.AbstractStage;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -45,7 +47,8 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
*
* @since 0.10.0
*/
-public class EntityAttributeAddingStage extends AbstractIteratingStage<Element> {
+ at ThreadSafe
+public class EntityAttributeAddingStage extends AbstractStage<Element> {
/** Class logger. */
private final Logger log = LoggerFactory.getLogger(EntityAttributeAddingStage.class);
@@ -55,7 +58,7 @@ public class EntityAttributeAddingStage extends AbstractIteratingStage<Element>
*
* The default value is for an entity attribute specifying an entity category.
*/
- @Nonnull
+ @Nonnull @GuardedBy("this")
private String attributeName = EntityCategorySupport.EC_CATEGORY_ATTR_NAME;
/**
@@ -63,11 +66,11 @@ public class EntityAttributeAddingStage extends AbstractIteratingStage<Element>
*
* The default value is suitable for most entity attributes.
*/
- @Nonnull
+ @Nonnull @GuardedBy("this")
private String attributeNameFormat = EntityCategorySupport.EC_ATTR_NAME_FORMAT;
/** The value of the attribute to be added. */
- @Nonnull
+ @Nonnull @GuardedBy("this")
private String attributeValue;
/**
@@ -76,23 +79,7 @@ public class EntityAttributeAddingStage extends AbstractIteratingStage<Element>
*
* Default: <code>false</code> (add as last child).
*/
- private boolean addingFirstChild;
-
- /** {@link Predicate} used to match existing Attribute elements. */
- @NonnullAfterInit
- private Predicate<Element> attributeMatcher;
-
- /** {@link Function} used to create new Attribute elements. */
- @NonnullAfterInit
- private Function<Container, Element> attributeMaker;
-
- /** {@link Predicate} used to match existing AttributeValue elements. */
- @NonnullAfterInit
- private Predicate<Element> attributeValueMatcher;
-
- /** {@link Function} used to create new AttributeValue elements. */
- @NonnullAfterInit
- private Function<Container, Element> attributeValueMaker;
+ @GuardedBy("this") private boolean addingFirstChild;
/**
* Returns the attribute name.
@@ -100,7 +87,7 @@ public class EntityAttributeAddingStage extends AbstractIteratingStage<Element>
* @return the attributeName
*/
@Nonnull
- public String getAttributeName() {
+ public final synchronized String getAttributeName() {
return attributeName;
}
@@ -109,7 +96,7 @@ public class EntityAttributeAddingStage extends AbstractIteratingStage<Element>
*
* @param name the attributeName to set
*/
- public void setAttributeName(@Nonnull final String name) {
+ public synchronized void setAttributeName(@Nonnull final String name) {
throwSetterPreconditionExceptions();
attributeName = Constraint.isNotNull(name, "attributeName must not be null");
}
@@ -120,7 +107,7 @@ public class EntityAttributeAddingStage extends AbstractIteratingStage<Element>
* @return the attributeNameFormat
*/
@Nonnull
- public String getAttributeNameFormat() {
+ public final synchronized String getAttributeNameFormat() {
return attributeNameFormat;
}
@@ -129,7 +116,7 @@ public class EntityAttributeAddingStage extends AbstractIteratingStage<Element>
*
* @param nameFormat the attributeNameFormat to set
*/
- public void setAttributeNameFormat(@Nonnull final String nameFormat) {
+ public synchronized void setAttributeNameFormat(@Nonnull final String nameFormat) {
throwSetterPreconditionExceptions();
attributeNameFormat = Constraint.isNotNull(nameFormat, "attributeNameFormat must not be null");
}
@@ -140,7 +127,7 @@ public class EntityAttributeAddingStage extends AbstractIteratingStage<Element>
* @return the attributeValue
*/
@Nonnull
- public String getAttributeValue() {
+ public final synchronized String getAttributeValue() {
return attributeValue;
}
@@ -149,7 +136,7 @@ public class EntityAttributeAddingStage extends AbstractIteratingStage<Element>
*
* @param value the attributeValue to set
*/
- public void setAttributeValue(@Nonnull final String value) {
+ public synchronized void setAttributeValue(@Nonnull final String value) {
throwSetterPreconditionExceptions();
attributeValue = Constraint.isNotNull(value, "attributeValue must not be null");
}
@@ -160,7 +147,7 @@ public class EntityAttributeAddingStage extends AbstractIteratingStage<Element>
*
* @return <code>true</code> if adding as the first child, <code>false</code> if the last
*/
- public boolean isAddingFirstChild() {
+ public final synchronized boolean isAddingFirstChild() {
return addingFirstChild;
}
@@ -170,7 +157,7 @@ public class EntityAttributeAddingStage extends AbstractIteratingStage<Element>
*
* @param addFirst <code>true</code> to add as the first child, <code>false</code> as the last
*/
- public void setAddingFirstChild(final boolean addFirst) {
+ public synchronized void setAddingFirstChild(final boolean addFirst) {
throwSetterPreconditionExceptions();
addingFirstChild = addFirst;
}
@@ -180,11 +167,13 @@ public class EntityAttributeAddingStage extends AbstractIteratingStage<Element>
* Attribute container elements.
*
* @param attributes {@link List} of Attribute {@link Container}s
+ * @param matcher
* @return true iff the value appears somewhere in the list of containers
*/
- private boolean attributeValuePresent(@Nonnull final List<Container> attributes) {
+ private boolean attributeValuePresent(@Nonnull final List<Container> attributes,
+ @Nonnull final Predicate<Element> matcher) {
for (final Container attribute : attributes) {
- if (attribute.findChild(attributeValueMatcher) != null) {
+ if (attribute.findChild(matcher) != null) {
return true;
}
}
@@ -192,37 +181,49 @@ public class EntityAttributeAddingStage extends AbstractIteratingStage<Element>
}
@Override
- 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;
+ protected void doExecute(@Nonnull @NonnullElements final Collection<Item<Element>> itemCollection) {
+ final var name = getAttributeName();
+ final var format = getAttributeNameFormat();
+ final var attributeMatcher = new AttributeElementMatcher(name, format);
+ final var attributeMaker = new AttributeElementMaker(name, format);
+
+ final var value = getAttributeValue();
+ final var attributeValueMatcher = new AttributeValueElementMatcher(value);
+ final var attributeValueMaker = new AttributeValueElementMaker(value);
+
+ for (final var 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,
+ isAddingFirstChild() ? 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, attributeValueMatcher)) {
+ 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);
}
-
- // 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);
}
}
@@ -234,19 +235,6 @@ public class EntityAttributeAddingStage extends AbstractIteratingStage<Element>
throw new ComponentInitializationException("attributeValue property must be supplied");
}
- attributeMatcher = new AttributeElementMatcher(attributeName, attributeNameFormat);
- attributeMaker = new AttributeElementMaker(attributeName, attributeNameFormat);
- attributeValueMatcher = new AttributeValueElementMatcher(attributeValue);
- attributeValueMaker = new AttributeValueElementMaker(attributeValue);
- }
-
- @Override
- protected void doDestroy() {
- attributeMatcher = null;
- attributeMaker = null;
- attributeValueMatcher = null;
- attributeValueMaker = null;
- super.doDestroy();
}
}
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 c392a44..2604492 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
@@ -22,6 +22,9 @@ import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
+import javax.annotation.concurrent.Immutable;
+import javax.annotation.concurrent.ThreadSafe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,6 +58,7 @@ import net.shibboleth.utilities.java.support.xml.ElementSupport;
*
* @since 0.9.0
*/
+ at ThreadSafe
public class EntityAttributeFilteringStage extends AbstractIteratingStage<Element> {
/** Class logger. */
@@ -106,6 +110,7 @@ public class EntityAttributeFilteringStage extends AbstractIteratingStage<Elemen
/**
* A simple immutable implementation of {@link EntityAttributeContext}.
*/
+ @Immutable
static class ContextImpl implements EntityAttributeContext {
/** The attribute's value. */
@@ -198,21 +203,21 @@ public class EntityAttributeFilteringStage extends AbstractIteratingStage<Elemen
* This amounts to an implicit ORing of the individual rules, with early
* termination.
*/
- @Nonnull @NonnullElements @Unmodifiable
+ @Nonnull @NonnullElements @Unmodifiable @GuardedBy("this")
private List<Predicate<EntityAttributeContext>> rules = List.of();
/** Mode of operation: whitelisting or blacklisting. Default: whitelisting. */
- private boolean whitelisting = true;
+ @GuardedBy("this") private boolean whitelisting = true;
/** Whether we add status metadata to the item when entity attributes are removed. Default: no. */
- private boolean recordingRemovals;
+ @GuardedBy("this") private boolean recordingRemovals;
/**
* Sets the {@link List} of rules to be used to match attribute values.
*
* @param newRules new {@link List} of rules
*/
- public void setRules(
+ public synchronized void setRules(
@Nonnull @NonnullElements @Unmodifiable final List<Predicate<EntityAttributeContext>> newRules) {
throwSetterPreconditionExceptions();
rules = List.copyOf(Constraint.isNotNull(newRules, "rules property may not be null"));
@@ -224,7 +229,7 @@ public class EntityAttributeFilteringStage extends AbstractIteratingStage<Elemen
* @return the {@link List} of rules
*/
@Nonnull @NonnullElements @Unmodifiable
- public List<Predicate<EntityAttributeContext>> getRules() {
+ public final synchronized List<Predicate<EntityAttributeContext>> getRules() {
return rules;
}
@@ -234,7 +239,7 @@ public class EntityAttributeFilteringStage extends AbstractIteratingStage<Elemen
* @param newValue <code>true</code> to whitelist (default),
* <code>false</code> to blacklist
*/
- public void setWhitelisting(final boolean newValue) {
+ public synchronized void setWhitelisting(final boolean newValue) {
throwSetterPreconditionExceptions();
whitelisting = newValue;
}
@@ -245,7 +250,7 @@ public class EntityAttributeFilteringStage extends AbstractIteratingStage<Elemen
* @return <code>true</code> if whitelisting (default),
* <code>false</code> if blacklisting
*/
- public boolean isWhitelisting() {
+ public final synchronized boolean isWhitelisting() {
return whitelisting;
}
@@ -254,7 +259,7 @@ public class EntityAttributeFilteringStage extends AbstractIteratingStage<Elemen
*
* @param newValue whether to remove recorded entity attributes
*/
- public void setRecordingRemovals(final boolean newValue) {
+ public synchronized void setRecordingRemovals(final boolean newValue) {
throwSetterPreconditionExceptions();
recordingRemovals = newValue;
}
@@ -265,7 +270,7 @@ public class EntityAttributeFilteringStage extends AbstractIteratingStage<Elemen
* @return <code>true</code> if recording,
* <code>false</code> if not (default)
*/
- public boolean isRecordingRemovals() {
+ public synchronized boolean isRecordingRemovals() {
return recordingRemovals;
}
@@ -277,7 +282,7 @@ public class EntityAttributeFilteringStage extends AbstractIteratingStage<Elemen
* otherwise <code>false</code>
*/
private boolean applyRules(final EntityAttributeContext ctx) {
- for (final Predicate<EntityAttributeContext> rule : rules) {
+ for (final Predicate<EntityAttributeContext> rule : getRules()) {
if (rule.test(ctx)) {
return true;
}
@@ -295,9 +300,8 @@ public class EntityAttributeFilteringStage extends AbstractIteratingStage<Elemen
final List<RegistrationAuthority> regAuthList = item.getItemMetadata().get(RegistrationAuthority.class);
if (regAuthList.isEmpty()) {
return null;
- } else {
- return regAuthList.get(0).getRegistrationAuthority();
}
+ return regAuthList.get(0).getRegistrationAuthority();
}
/**
@@ -328,9 +332,9 @@ public class EntityAttributeFilteringStage extends AbstractIteratingStage<Elemen
new ContextImpl(attributeValue, attributeName,
attributeNameFormat, registrationAuthority);
final boolean matched = applyRules(ctx);
- if (matched ^ whitelisting) {
+ if (matched ^ isWhitelisting()) {
log.debug("removing {}", ctx);
- if (recordingRemovals) {
+ if (isRecordingRemovals()) {
item.getItemMetadata().put(new WarningStatus(getId(),
"removing '" + ctx.getName() + "' = '" + ctx.getValue() + "'"));
}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/EntityCategoryMatcher.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/EntityCategoryMatcher.java
index ab0f18c..5b4eced 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/EntityCategoryMatcher.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/EntityCategoryMatcher.java
@@ -19,14 +19,14 @@ package net.shibboleth.metadata.dom.saml.mdattr;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import javax.annotation.concurrent.ThreadSafe;
+import javax.annotation.concurrent.Immutable;
/**
* An entity attribute matcher which matches a given entity category.
*
* @since 0.9.0
*/
- at ThreadSafe
+ at Immutable
public class EntityCategoryMatcher extends AbstractExactValueMatcher {
/**
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/EntityCategorySupportMatcher.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/EntityCategorySupportMatcher.java
index 2a2cc21..8b355ad 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/EntityCategorySupportMatcher.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/EntityCategorySupportMatcher.java
@@ -19,14 +19,14 @@ package net.shibboleth.metadata.dom.saml.mdattr;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import javax.annotation.concurrent.ThreadSafe;
+import javax.annotation.concurrent.Immutable;
/**
* An entity attribute matcher which matches a given entity support category.
*
* @since 0.9.0
*/
- at ThreadSafe
+ at Immutable
public class EntityCategorySupportMatcher extends AbstractExactValueMatcher {
/**
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/MultiPredicateMatcher.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/MultiPredicateMatcher.java
index 9ca1707..f634c22 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/MultiPredicateMatcher.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/MultiPredicateMatcher.java
@@ -21,6 +21,7 @@ import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -40,19 +41,19 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
public class MultiPredicateMatcher extends AbstractEntityAttributeMatcher {
/** {@link Predicate} to use to match the context's attribute value. */
- @Nonnull
+ @Nonnull @GuardedBy("this")
private Predicate<CharSequence> valuePredicate = x -> true;
/** {@link Predicate} to use to match the context's attribute name. */
- @Nonnull
+ @Nonnull @GuardedBy("this")
private Predicate<CharSequence> namePredicate = x -> true;
/** {@link Predicate} to use to match the context's attribute name format. */
- @Nonnull
+ @Nonnull @GuardedBy("this")
private Predicate<CharSequence> nameFormatPredicate = x -> true;
/** {@link Predicate} to use to match the context's registration authority. */
- @Nonnull
+ @Nonnull @GuardedBy("this")
private Predicate<CharSequence> registrationAuthorityPredicate = x -> true;
/**
@@ -61,7 +62,7 @@ public class MultiPredicateMatcher extends AbstractEntityAttributeMatcher {
* @return the {@link Predicate} being used to match the context's attribute value
*/
@Nonnull
- public Predicate<CharSequence> getValuePredicate() {
+ public final synchronized Predicate<CharSequence> getValuePredicate() {
return valuePredicate;
}
@@ -70,7 +71,7 @@ public class MultiPredicateMatcher extends AbstractEntityAttributeMatcher {
*
* @param predicate new {@link Predicate} to use to match the context's attribute value
*/
- public void setValuePredicate(@Nonnull final Predicate<CharSequence> predicate) {
+ public synchronized void setValuePredicate(@Nonnull final Predicate<CharSequence> predicate) {
valuePredicate = Constraint.isNotNull(predicate, "value predicate may not be null");
}
@@ -80,7 +81,7 @@ public class MultiPredicateMatcher extends AbstractEntityAttributeMatcher {
* @return the {@link Predicate} being used to match the context's attribute name
*/
@Nonnull
- public Predicate<CharSequence> getNamePredicate() {
+ public final synchronized Predicate<CharSequence> getNamePredicate() {
return namePredicate;
}
@@ -89,7 +90,7 @@ public class MultiPredicateMatcher extends AbstractEntityAttributeMatcher {
*
* @param predicate new {@link Predicate} to use to match the context's attribute name
*/
- public void setNamePredicate(@Nonnull final Predicate<CharSequence> predicate) {
+ public synchronized void setNamePredicate(@Nonnull final Predicate<CharSequence> predicate) {
namePredicate = Constraint.isNotNull(predicate, "name predicate may not be null");
}
@@ -99,7 +100,7 @@ public class MultiPredicateMatcher extends AbstractEntityAttributeMatcher {
* @return the {@link Predicate} being used to match the context's attribute name format
*/
@Nonnull
- public Predicate<CharSequence> getNameFormatPredicate() {
+ public final synchronized Predicate<CharSequence> getNameFormatPredicate() {
return nameFormatPredicate;
}
@@ -108,7 +109,7 @@ public class MultiPredicateMatcher extends AbstractEntityAttributeMatcher {
*
* @param predicate new {@link Predicate} to use to match the context's attribute name format
*/
- public void setNameFormatPredicate(@Nonnull final Predicate<CharSequence> predicate) {
+ public synchronized void setNameFormatPredicate(@Nonnull final Predicate<CharSequence> predicate) {
nameFormatPredicate = Constraint.isNotNull(predicate, "name format predicate may not be null");
}
@@ -118,8 +119,8 @@ public class MultiPredicateMatcher extends AbstractEntityAttributeMatcher {
* @return the {@link Predicate} being used to match the context's registration authority
*/
@Nonnull
- public Predicate<CharSequence> getRegistrationAuthorityPredicate() {
- return valuePredicate;
+ public final synchronized Predicate<CharSequence> getRegistrationAuthorityPredicate() {
+ return registrationAuthorityPredicate;
}
/**
@@ -127,29 +128,29 @@ public class MultiPredicateMatcher extends AbstractEntityAttributeMatcher {
*
* @param predicate new {@link Predicate} to use to match the context's registration authority
*/
- public void setRegistrationAuthorityPredicate(@Nonnull final Predicate<CharSequence> predicate) {
+ public synchronized void setRegistrationAuthorityPredicate(@Nonnull final Predicate<CharSequence> predicate) {
registrationAuthorityPredicate = Constraint.isNotNull(predicate,
"registration authority predicate may not be null");
}
@Override
protected boolean matchAttributeValue(@Nonnull final String inputValue) {
- return valuePredicate.test(inputValue);
+ return getValuePredicate().test(inputValue);
}
@Override
protected boolean matchAttributeName(@Nonnull final String inputName) {
- return namePredicate.test(inputName);
+ return getNamePredicate().test(inputName);
}
@Override
protected boolean matchAttributeNameFormat(@Nonnull final String inputNameFormat) {
- return nameFormatPredicate.test(inputNameFormat);
+ return getNameFormatPredicate().test(inputNameFormat);
}
@Override
protected boolean matchRegistrationAuthority(@Nullable final String inputRegistrationAuthority) {
- return registrationAuthorityPredicate.test(inputRegistrationAuthority);
+ return getRegistrationAuthorityPredicate().test(inputRegistrationAuthority);
}
}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/RegistrationAuthorityMatcher.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/RegistrationAuthorityMatcher.java
index 621350c..90a962b 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/RegistrationAuthorityMatcher.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdattr/RegistrationAuthorityMatcher.java
@@ -21,7 +21,7 @@ import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import javax.annotation.concurrent.ThreadSafe;
+import javax.annotation.concurrent.Immutable;
import net.shibboleth.metadata.dom.saml.mdattr.EntityAttributeFilteringStage.EntityAttributeContext;
@@ -33,7 +33,7 @@ import net.shibboleth.metadata.dom.saml.mdattr.EntityAttributeFilteringStage.Ent
*
* @since 0.9.0
*/
- at ThreadSafe
+ at Immutable
public class RegistrationAuthorityMatcher implements Predicate<EntityAttributeContext> {
/** Registration authority to match against. */
@@ -54,9 +54,8 @@ public class RegistrationAuthorityMatcher implements Predicate<EntityAttributeCo
if (registrationAuthority == null) {
// match entities *without* a registration authority
return null == input.getRegistrationAuthority();
- } else {
- return registrationAuthority.equals(input.getRegistrationAuthority());
}
+ return registrationAuthority.equals(input.getRegistrationAuthority());
}
}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdrpi/EntityRegistrationAuthorityFilterStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdrpi/EntityRegistrationAuthorityFilterStage.java
index f28111b..1cf5cc3 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdrpi/EntityRegistrationAuthorityFilterStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdrpi/EntityRegistrationAuthorityFilterStage.java
@@ -23,6 +23,7 @@ import java.util.List;
import java.util.Set;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import org.slf4j.Logger;
@@ -45,24 +46,24 @@ public class EntityRegistrationAuthorityFilterStage extends AbstractFilteringSta
private final Logger log = LoggerFactory.getLogger(EntityRegistrationAuthorityFilterStage.class);
/** Whether a descriptor is required to have registration information. Default value: false */
- private boolean requiringRegistrationInformation;
+ @GuardedBy("this") private boolean requiringRegistrationInformation;
/** Registrars which are white/black listed depending on the value of {@link #whitelistingAuthorities}. */
- @Nonnull @NonnullElements @Unmodifiable
+ @Nonnull @NonnullElements @Unmodifiable @GuardedBy("this")
private Set<String> designatedAuthorities = Set.of();
/** Whether {@link #designatedAuthorities} should be considered a whitelist or a blacklist. Default value: false */
- private boolean whitelistingAuthorities;
+ @GuardedBy("this") private boolean whitelistingAuthorities;
/** Whether EntitiesDescriptor that do not contain EntityDescriptors should be removed. Default value: true */
- private boolean removingEntitylessEntitiesDescriptor = true;
+ @GuardedBy("this") private boolean removingEntitylessEntitiesDescriptor = true;
/**
* Gets whether a descriptor is required to have registration information.
*
* @return whether a descriptor is required to have registration information
*/
- public boolean isRequiringRegistrationInformation() {
+ public final synchronized boolean isRequiringRegistrationInformation() {
return requiringRegistrationInformation;
}
@@ -82,7 +83,7 @@ public class EntityRegistrationAuthorityFilterStage extends AbstractFilteringSta
* @return list of designated registration authority, never null
*/
@Nonnull @NonnullElements @Unmodifiable
- public Collection<String> getDesignatedRegistrationAuthorities() {
+ public final synchronized Collection<String> getDesignatedRegistrationAuthorities() {
return designatedAuthorities;
}
@@ -102,7 +103,7 @@ public class EntityRegistrationAuthorityFilterStage extends AbstractFilteringSta
*
* @return true if the designated registration authority should be considered a whitelist, false otherwise
*/
- public boolean isWhitelistingRegistrationAuthorities() {
+ public final synchronized boolean isWhitelistingRegistrationAuthorities() {
return whitelistingAuthorities;
}
@@ -122,7 +123,7 @@ public class EntityRegistrationAuthorityFilterStage extends AbstractFilteringSta
*
* @return whether EntitiesDescriptor that do not contain EntityDescriptors should be removed
*/
- public boolean isRemovingEntitylessEntitiesDescriptor() {
+ public final synchronized boolean isRemovingEntitylessEntitiesDescriptor() {
return removingEntitylessEntitiesDescriptor;
}
@@ -136,13 +137,6 @@ public class EntityRegistrationAuthorityFilterStage extends AbstractFilteringSta
removingEntitylessEntitiesDescriptor = remove;
}
- @Override
- protected void doDestroy() {
- designatedAuthorities = null;
-
- super.doDestroy();
- }
-
@Override
protected boolean doExecute(@Nonnull final Item<Element> item) {
final Element descriptor;
@@ -198,8 +192,8 @@ public class EntityRegistrationAuthorityFilterStage extends AbstractFilteringSta
}
}
- if (removingEntitylessEntitiesDescriptor && childEntitiesDescriptors.isEmpty()
- && childEntityDescriptors.isEmpty()) {
+ if (childEntitiesDescriptors.isEmpty() && childEntityDescriptors.isEmpty() &&
+ isRemovingEntitylessEntitiesDescriptor()) {
return true;
}
@@ -223,15 +217,14 @@ public class EntityRegistrationAuthorityFilterStage extends AbstractFilteringSta
final Element registrationInfoElement =
SAMLMetadataSupport.getDescriptorExtension(descriptor, MDRPIMetadataSupport.MDRPI_REGISTRATION_INFO);
if (registrationInfoElement == null) {
- if (requiringRegistrationInformation) {
+ if (isRequiringRegistrationInformation()) {
log.debug(
"{} pipeline stage removing Item because it did not have " +
"required registration information extension",
getId());
return true;
- } else {
- return false;
}
+ return false;
}
final String registrationAuthority =
@@ -244,13 +237,15 @@ public class EntityRegistrationAuthorityFilterStage extends AbstractFilteringSta
return true;
}
- if (whitelistingAuthorities && !designatedAuthorities.contains(registrationAuthority)) {
+ if (isWhitelistingRegistrationAuthorities() &&
+ !getDesignatedRegistrationAuthorities().contains(registrationAuthority)) {
log.debug("{} pipeline stage removing Item because its registration authority was not on the whitelist",
getId());
return true;
}
- if (!whitelistingAuthorities && designatedAuthorities.contains(registrationAuthority)) {
+ if (!isWhitelistingRegistrationAuthorities() &&
+ getDesignatedRegistrationAuthorities().contains(registrationAuthority)) {
log.debug("{} pipeline stage removing Item because its registration authority was on the blacklist",
getId());
return true;
@@ -258,4 +253,12 @@ public class EntityRegistrationAuthorityFilterStage extends AbstractFilteringSta
return false;
}
+
+ @Override
+ protected void doDestroy() {
+ designatedAuthorities = null;
+
+ super.doDestroy();
+ }
+
}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdrpi/RegistrationAuthorityItemIdentificationStrategy.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdrpi/RegistrationAuthorityItemIdentificationStrategy.java
index af9a83d..539d2af 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdrpi/RegistrationAuthorityItemIdentificationStrategy.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdrpi/RegistrationAuthorityItemIdentificationStrategy.java
@@ -24,6 +24,7 @@ import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import net.shibboleth.metadata.FirstItemIdItemIdentificationStrategy;
@@ -49,13 +50,13 @@ public class RegistrationAuthorityItemIdentificationStrategy extends FirstItemId
/**
* Set of registration authorities to be ignored.
*/
- @Nonnull @NonnullElements @Unmodifiable
+ @Nonnull @NonnullElements @Unmodifiable @GuardedBy("this")
private Set<String> ignoredRegistrationAuthorities = Set.of();
/**
* Replacement display names for registration authorities.
*/
- @Nonnull @NonnullElements @Unmodifiable
+ @Nonnull @NonnullElements @Unmodifiable @GuardedBy("this")
private Map<String, String> registrationAuthorityDisplayNames = Map.of();
/**
@@ -64,7 +65,7 @@ public class RegistrationAuthorityItemIdentificationStrategy extends FirstItemId
* @return {@link Set} of registration authority names.
*/
@Nonnull @NonnullElements @Unmodifiable
- public Collection<String> getIgnoredRegistrationAuthorities() {
+ public final synchronized Collection<String> getIgnoredRegistrationAuthorities() {
return ignoredRegistrationAuthorities;
}
@@ -73,7 +74,7 @@ public class RegistrationAuthorityItemIdentificationStrategy extends FirstItemId
*
* @param registrars {@link Set} of registration authority names to ignore.
*/
- public void setIgnoredRegistrationAuthorities(
+ public synchronized void setIgnoredRegistrationAuthorities(
@Nonnull @NonnullElements @Unmodifiable final Collection<String> registrars) {
ignoredRegistrationAuthorities = Set.copyOf(registrars);
}
@@ -84,7 +85,7 @@ public class RegistrationAuthorityItemIdentificationStrategy extends FirstItemId
* @return {@link Map} of display names for authorities.
*/
@Nonnull @NonnullElements @Unmodifiable
- public Map<String, String> getRegistrationAuthorityDisplayNames() {
+ public final synchronized Map<String, String> getRegistrationAuthorityDisplayNames() {
return registrationAuthorityDisplayNames;
}
@@ -93,7 +94,7 @@ public class RegistrationAuthorityItemIdentificationStrategy extends FirstItemId
*
* @param names {@link Map} of display names for registration authorities.
*/
- public void setRegistrationAuthorityDisplayNames(
+ public synchronized void setRegistrationAuthorityDisplayNames(
@Nonnull @NonnullElements @Unmodifiable final Map<String, String> names) {
registrationAuthorityDisplayNames = Map.copyOf(names);
}
@@ -117,17 +118,16 @@ public class RegistrationAuthorityItemIdentificationStrategy extends FirstItemId
final String regAuth = regAuths.get(0).getRegistrationAuthority();
// nothing to return if it's an ignored authority
- if (ignoredRegistrationAuthorities.contains(regAuth)) {
+ if (getIgnoredRegistrationAuthorities().contains(regAuth)) {
return null;
}
// handle mapping it to a simpler form if that's available
- final String displayName = registrationAuthorityDisplayNames.get(regAuth);
+ final String displayName = getRegistrationAuthorityDisplayNames().get(regAuth);
if (displayName != null) {
return displayName;
- } else {
- return regAuth;
}
+ return regAuth;
}
}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdui/IPHintValidationStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdui/IPHintValidationStage.java
index 23c04c6..61e4be7 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdui/IPHintValidationStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/dom/saml/mdui/IPHintValidationStage.java
@@ -18,6 +18,7 @@
package net.shibboleth.metadata.dom.saml.mdui;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import org.w3c.dom.Element;
@@ -38,14 +39,14 @@ import net.shibboleth.utilities.java.support.xml.ElementSupport;
public class IPHintValidationStage extends AbstractDOMTraversalStage<DOMTraversalContext> {
/** Whether to check that the CIDR notation describes a network. Defaults to true. */
- private boolean checkingNetworks = true;
+ @GuardedBy("this") private boolean checkingNetworks = true;
/**
* Gets whether the stage is checking for network addresses only.
*
* @return whether the stage is checking for network addresses only
*/
- public boolean isCheckingNetworks() {
+ public final synchronized boolean isCheckingNetworks() {
return checkingNetworks;
}
@@ -54,7 +55,7 @@ public class IPHintValidationStage extends AbstractDOMTraversalStage<DOMTraversa
*
* @param check whether to check for network addresses only
*/
- public void setCheckingNetworks(final boolean check) {
+ public synchronized void setCheckingNetworks(final boolean check) {
throwSetterPreconditionExceptions();
this.checkingNetworks = check;
}
@@ -71,7 +72,7 @@ public class IPHintValidationStage extends AbstractDOMTraversalStage<DOMTraversa
final String hint = ipHint.getTextContent();
try {
final IPRange range = IPRange.parseCIDRBlock(hint);
- if (checkingNetworks) {
+ if (isCheckingNetworks()) {
if (range.getHostAddress() != null) {
addError(context.getItem(), ipHint, "invalid IPHint '" + hint +
"': CIDR notation represents a host, not a network");
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/AbstractItemMetadataSelectionStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/AbstractItemMetadataSelectionStage.java
index 9ec78e8..3b17e0c 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/AbstractItemMetadataSelectionStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/AbstractItemMetadataSelectionStage.java
@@ -25,6 +25,7 @@ import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import net.shibboleth.metadata.FirstItemIdItemIdentificationStrategy;
@@ -47,10 +48,11 @@ public abstract class AbstractItemMetadataSelectionStage<T> extends AbstractStag
/**
* {@link ItemMetadata} classes that, if an item contains them, will cause the {@link Item} to be selected.
*/
- @Nonnull @NonnullElements @Unmodifiable
+ @Nonnull @NonnullElements @Unmodifiable @GuardedBy("this")
private Set<Class<? extends ItemMetadata>> selectionRequirements = Set.of();
/** Strategy used to generate item identifiers for logging purposes. */
+ @Nonnull @GuardedBy("this")
private ItemIdentificationStrategy identificationStrategy = new FirstItemIdItemIdentificationStrategy();
/**
@@ -61,7 +63,7 @@ public abstract class AbstractItemMetadataSelectionStage<T> extends AbstractStag
* selected, never null nor containing null elements
*/
@Nonnull @NonnullElements @Unmodifiable
- public Collection<Class<? extends ItemMetadata>> getSelectionRequirements() {
+ public final synchronized Collection<Class<? extends ItemMetadata>> getSelectionRequirements() {
return selectionRequirements;
}
@@ -83,7 +85,7 @@ public abstract class AbstractItemMetadataSelectionStage<T> extends AbstractStag
*
* @return strategy used to generate {@link Item} identifiers for logging purposes
*/
- @Nonnull public ItemIdentificationStrategy getItemIdentificationStrategy() {
+ @Nonnull public final synchronized ItemIdentificationStrategy getItemIdentificationStrategy() {
return identificationStrategy;
}
@@ -107,7 +109,7 @@ public abstract class AbstractItemMetadataSelectionStage<T> extends AbstractStag
final HashMap<Class<? extends ItemMetadata>, List<? extends ItemMetadata>> matchingMetadata =
new HashMap<>();
- for (final Class<? extends ItemMetadata> infoClass : selectionRequirements) {
+ for (final Class<? extends ItemMetadata> infoClass : getSelectionRequirements()) {
if (item.getItemMetadata().containsKey(infoClass)) {
matchingMetadata.put(infoClass, item.getItemMetadata().get(infoClass));
}
@@ -136,12 +138,11 @@ public abstract class AbstractItemMetadataSelectionStage<T> extends AbstractStag
*
* @throws StageProcessingException thrown if there is a problem processing the item
*/
- protected abstract
- void
- doExecute(
- @Nonnull @NonnullElements final Collection<Item<T>> itemCollection,
- @Nonnull final Item<T> matchingItem,
- @Nonnull @NonnullElements
- final Map<Class<? extends ItemMetadata>, List<? extends ItemMetadata>> matchingMetadata)
+ protected abstract void doExecute(
+ @Nonnull @NonnullElements final Collection<Item<T>> itemCollection,
+ @Nonnull final Item<T> matchingItem,
+ @Nonnull @NonnullElements
+ final Map<Class<? extends ItemMetadata>, List<? extends ItemMetadata>> matchingMetadata)
throws StageProcessingException;
+
}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/AbstractStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/AbstractStage.java
index bfffc89..5393f62 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/AbstractStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/AbstractStage.java
@@ -22,6 +22,7 @@ import java.util.Collection;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import net.shibboleth.metadata.Item;
@@ -41,7 +42,7 @@ public abstract class AbstractStage<T> extends BaseIdentifiableInitializableComp
* The {@link Predicate} applied to the supplied item collection to determine whether the stage will be executed.
* Default value: always <code>true</code>.
*/
- @Nonnull
+ @Nonnull @GuardedBy("this")
private Predicate<Collection<Item<T>>> collectionPredicate = x -> true;
/**
@@ -51,7 +52,7 @@ public abstract class AbstractStage<T> extends BaseIdentifiableInitializableComp
* @param pred the {@link Predicate} applied to the supplied item collection to determine
* whether the stage will be executed
*/
- public void setCollectionPredicate(@Nonnull final Predicate<Collection<Item<T>>> pred) {
+ public synchronized void setCollectionPredicate(@Nonnull final Predicate<Collection<Item<T>>> pred) {
throwSetterPreconditionExceptions();
collectionPredicate = Constraint.isNotNull(pred, "collectionPredicate may not be null");
}
@@ -64,7 +65,7 @@ public abstract class AbstractStage<T> extends BaseIdentifiableInitializableComp
* the stage will be executed.
*/
@Nonnull
- public Predicate<Collection<Item<T>>> getCollectionPredicate() {
+ public final synchronized Predicate<Collection<Item<T>>> getCollectionPredicate() {
return collectionPredicate;
}
@@ -75,7 +76,7 @@ public abstract class AbstractStage<T> extends BaseIdentifiableInitializableComp
final var start = Instant.now();
- if (collectionPredicate.test(itemCollection)) {
+ if (getCollectionPredicate().test(itemCollection)) {
doExecute(itemCollection);
}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/AtLeastCollectionPredicate.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/AtLeastCollectionPredicate.java
index 6433b43..37f4820 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/AtLeastCollectionPredicate.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/AtLeastCollectionPredicate.java
@@ -20,6 +20,9 @@ package net.shibboleth.metadata.pipeline;
import java.util.Collection;
import java.util.function.Predicate;
+import javax.annotation.concurrent.GuardedBy;
+import javax.annotation.concurrent.ThreadSafe;
+
/**
* A {@link Predicate} which returns <code>true</code> if and only if the number of elements
* in the supplied collection is at least the configured minimum value.
@@ -28,12 +31,13 @@ import java.util.function.Predicate;
*
* @since 0.9.0
*/
+ at ThreadSafe
public class AtLeastCollectionPredicate<T> implements Predicate<Collection<T>> {
/**
* Minimum element count which will satisfy the condition. Default value: 0.
*/
- private int minimum;
+ @GuardedBy("this") private int minimum;
/**
* Returns the minimum number of elements which will result in a <code>true</code>
@@ -42,7 +46,7 @@ public class AtLeastCollectionPredicate<T> implements Predicate<Collection<T>> {
* @return the minimum number of elements which will result in a <code>true</code>
* result.
*/
- public int getMinimum() {
+ public final synchronized int getMinimum() {
return minimum;
}
@@ -53,13 +57,13 @@ public class AtLeastCollectionPredicate<T> implements Predicate<Collection<T>> {
* @param min minimum number of elements which will result in a <code>true</code>
* result.
*/
- public void setMinimum(final int min) {
+ public synchronized void setMinimum(final int min) {
minimum = min;
}
@Override
public boolean test(final Collection<T> input) {
- return input.size() >= minimum;
+ return input.size() >= getMinimum();
}
}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/CompositeStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/CompositeStage.java
index ee4c243..18991b4 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/CompositeStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/CompositeStage.java
@@ -21,6 +21,7 @@ import java.util.Collection;
import java.util.List;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import net.shibboleth.metadata.Item;
@@ -37,7 +38,7 @@ import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
public class CompositeStage<T> extends AbstractStage<T> {
/** Stages which compose this stage. */
- @Nonnull @NonnullElements @Unmodifiable
+ @Nonnull @NonnullElements @Unmodifiable @GuardedBy("this")
private List<Stage<T>> composedStages = List.of();
@@ -47,7 +48,7 @@ public class CompositeStage<T> extends AbstractStage<T> {
* @return list the stages that compose this stage, never null nor containing null elements
*/
@Nonnull @NonnullElements @Unmodifiable
- public List<Stage<T>> getComposedStages() {
+ public final synchronized List<Stage<T>> getComposedStages() {
return composedStages;
}
@@ -65,7 +66,7 @@ public class CompositeStage<T> extends AbstractStage<T> {
@Override
protected void doExecute(@Nonnull @NonnullElements final Collection<Item<T>> itemCollection)
throws StageProcessingException {
- for (final Stage<T> stage : composedStages) {
+ for (final Stage<T> stage : getComposedStages()) {
stage.execute(itemCollection);
}
}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/FilesInDirectoryMultiOutputStrategy.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/FilesInDirectoryMultiOutputStrategy.java
index be8adc9..7a546cc 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/FilesInDirectoryMultiOutputStrategy.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/FilesInDirectoryMultiOutputStrategy.java
@@ -25,6 +25,9 @@ import java.util.List;
import java.util.function.Function;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
+import javax.annotation.concurrent.Immutable;
+import javax.annotation.concurrent.ThreadSafe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -53,6 +56,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
*
* @since 0.9.2
*/
+ at ThreadSafe
public class FilesInDirectoryMultiOutputStrategy<T> extends BaseInitializableComponent
implements MultiOutputSerializationStage.OutputStrategy<T> {
@@ -62,10 +66,11 @@ public class FilesInDirectoryMultiOutputStrategy<T> extends BaseInitializableCom
/**
* Class implementing the returned {@link MultiOutputSerializationStage.Destination} objects.
*/
+ @Immutable
private class FileDestination implements MultiOutputSerializationStage.Destination {
/** The destination {@link File}. */
- private final File file;
+ @Nonnull private final File file;
/**
* Constructor.
@@ -87,23 +92,23 @@ public class FilesInDirectoryMultiOutputStrategy<T> extends BaseInitializableCom
}
/** String to use as a prefix for file names generated by this strategy. Default value: empty string. */
- @Nonnull private String namePrefix = "";
+ @Nonnull @GuardedBy("this") private String namePrefix = "";
/** {@link Function} to use to transform the {@link Item}'s {@link ItemId}. Default: identity transform. */
- @Nonnull private Function<String, String> nameTransformer = x -> x;
+ @Nonnull @GuardedBy("this") private Function<String, String> nameTransformer = x -> x;
/** String to use as a suffix for file names generated by this strategy. Default value: empty string. */
- @Nonnull private String nameSuffix = "";
+ @Nonnull @GuardedBy("this") private String nameSuffix = "";
/** Directory into which to write files. */
- @NonnullAfterInit private File directory;
+ @NonnullAfterInit @GuardedBy("this") private File directory;
/**
* Gets the name prefix in use.
*
* @return the name prefix in use
*/
- @Nonnull public String getNamePrefix() {
+ @Nonnull public final synchronized String getNamePrefix() {
return namePrefix;
}
@@ -112,7 +117,7 @@ public class FilesInDirectoryMultiOutputStrategy<T> extends BaseInitializableCom
*
* @param prefix the name prefix to use
*/
- public void setNamePrefix(@Nonnull final String prefix) {
+ public synchronized void setNamePrefix(@Nonnull final String prefix) {
throwSetterPreconditionExceptions();
namePrefix = Constraint.isNotNull(prefix, "name prefix may not be null");
}
@@ -122,7 +127,7 @@ public class FilesInDirectoryMultiOutputStrategy<T> extends BaseInitializableCom
*
* @return the name transformer in use.
*/
- @Nonnull public Function<String, String> getNameTransformer() {
+ @Nonnull public final synchronized Function<String, String> getNameTransformer() {
return nameTransformer;
}
@@ -131,7 +136,7 @@ public class FilesInDirectoryMultiOutputStrategy<T> extends BaseInitializableCom
*
* @param transformer the name transformer to use
*/
- public void setNameTransformer(@Nonnull final Function<String, String> transformer) {
+ public synchronized void setNameTransformer(@Nonnull final Function<String, String> transformer) {
throwSetterPreconditionExceptions();
nameTransformer = Constraint.isNotNull(transformer,
"name transformer may not be null");
@@ -142,7 +147,7 @@ public class FilesInDirectoryMultiOutputStrategy<T> extends BaseInitializableCom
*
* @return the name suffix in use
*/
- @Nonnull public String getNameSuffix() {
+ @Nonnull public final synchronized String getNameSuffix() {
return nameSuffix;
}
@@ -151,7 +156,7 @@ public class FilesInDirectoryMultiOutputStrategy<T> extends BaseInitializableCom
*
* @param suffix the name suffix to use
*/
- public void setNameSuffix(@Nonnull final String suffix) {
+ public synchronized void setNameSuffix(@Nonnull final String suffix) {
throwSetterPreconditionExceptions();
nameSuffix = Constraint.isNotNull(suffix, "name suffix may not be null");
}
@@ -161,7 +166,7 @@ public class FilesInDirectoryMultiOutputStrategy<T> extends BaseInitializableCom
*
* @return the directory in use
*/
- @Nonnull public File getDirectory() {
+ @Nonnull public final synchronized File getDirectory() {
return directory;
}
@@ -170,7 +175,7 @@ public class FilesInDirectoryMultiOutputStrategy<T> extends BaseInitializableCom
*
* @param dir the directory to use
*/
- public void setDirectory(@Nonnull final File dir) {
+ public synchronized void setDirectory(@Nonnull final File dir) {
throwSetterPreconditionExceptions();
directory = Constraint.isNotNull(dir, "directory may not be null");
}
@@ -185,11 +190,11 @@ public class FilesInDirectoryMultiOutputStrategy<T> extends BaseInitializableCom
final ItemId id = ids.get(0);
// Construct file name
- final String name = namePrefix + nameTransformer.apply(id.getId()) + nameSuffix;
+ final String name = getNamePrefix() + getNameTransformer().apply(id.getId()) + getNameSuffix();
log.debug("id mapped {} -> {}", id.getId(), name);
// Locate the output file within the directory
- final File outputFile = new File(directory, name);
+ final File outputFile = new File(getDirectory(), name);
return new FileDestination(outputFile);
}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/FutureSupport.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/FutureSupport.java
index e4c00f0..d2bd558 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/FutureSupport.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/FutureSupport.java
@@ -24,6 +24,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.ThreadSafe;
import org.slf4j.Logger;
@@ -43,6 +44,7 @@ public final class FutureSupport {
*
* @param <T> type of "future" object to return
*/
+ @Immutable
private static class FutureNow<T> implements Future<T> {
/**
@@ -130,10 +132,9 @@ public final class FutureSupport {
if (e.getCause() instanceof StageProcessingException) {
// UN-wrap our own exceptions so as to propagate them
throw (StageProcessingException) e.getCause();
- } else {
- // Wrap other exceptions
- throw new StageProcessingException("ExecutionException during processing", e);
}
+ // Wrap other exceptions
+ throw new StageProcessingException("ExecutionException during processing", e);
} catch (final InterruptedException e) {
LOG.debug("Execution service was interrupted", e);
throw new StageProcessingException("Execution service was interrupted", e);
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 e527bb9..04ab05b 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
@@ -23,6 +23,7 @@ import java.util.List;
import java.util.function.Function;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import net.shibboleth.metadata.Item;
@@ -43,7 +44,7 @@ import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
public class ItemIdTransformStage<T> extends AbstractIteratingStage<T> {
/** Transformers used on IDs. */
- @Nonnull @NonnullElements @Unmodifiable
+ @Nonnull @NonnullElements @Unmodifiable @GuardedBy("this")
private List<Function<String, String>> idTransformers = List.of();
/**
@@ -52,7 +53,7 @@ public class ItemIdTransformStage<T> extends AbstractIteratingStage<T> {
* @return transforms used to produce the transformed entity IDs, never null
*/
@Nonnull @NonnullElements @Unmodifiable
- public Collection<Function<String, String>> getIdTransformers() {
+ public final synchronized Collection<Function<String, String>> getIdTransformers() {
return idTransformers;
}
@@ -73,7 +74,7 @@ public class ItemIdTransformStage<T> extends AbstractIteratingStage<T> {
final List<ItemId> transformedIds = new ArrayList<>();
for (final ItemId id : ids) {
- for (final Function<String, String> idTransform : idTransformers) {
+ for (final Function<String, String> idTransform : getIdTransformers()) {
final String transformedId = idTransform.apply(id.getId());
transformedIds.add(new ItemId(transformedId));
}
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 c6f0893..8854afd 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
@@ -21,6 +21,7 @@ import java.util.Collection;
import java.util.List;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import net.shibboleth.metadata.Item;
@@ -40,7 +41,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
public class ItemMetadataAddingStage<T> extends AbstractIteratingStage<T> {
/** {@link ItemMetadata} objects to add to each {@link Item}'s item metadata. */
- @Nonnull @NonnullElements @Unmodifiable
+ @Nonnull @NonnullElements @Unmodifiable @GuardedBy("this")
private List<ItemMetadata> additionalItemMetadata = List.of();
/**
@@ -49,7 +50,7 @@ public class ItemMetadataAddingStage<T> extends AbstractIteratingStage<T> {
* @return the {@link ItemMetadata} being added to each {@link Item}'s item metadata
*/
@Nonnull @NonnullElements @Unmodifiable
- public Collection<ItemMetadata> getAdditionalItemMetadata() {
+ public final synchronized Collection<ItemMetadata> getAdditionalItemMetadata() {
return additionalItemMetadata;
}
@@ -58,7 +59,7 @@ public class ItemMetadataAddingStage<T> extends AbstractIteratingStage<T> {
*
* @param metadata the {@link ItemMetadata} to be added to each {@link Item}'s item metadata
*/
- public void setAdditionalItemMetadata(
+ public synchronized void setAdditionalItemMetadata(
@Nonnull @NonnullElements @Unmodifiable final Collection<ItemMetadata> metadata) {
throwSetterPreconditionExceptions();
@@ -68,6 +69,6 @@ public class ItemMetadataAddingStage<T> extends AbstractIteratingStage<T> {
@Override
protected void doExecute(@Nonnull final Item<T> item) throws StageProcessingException {
- item.getItemMetadata().putAll(additionalItemMetadata);
+ item.getItemMetadata().putAll(getAdditionalItemMetadata());
}
}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemMetadataFilterStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemMetadataFilterStage.java
index 1a26925..cf7607e 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemMetadataFilterStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemMetadataFilterStage.java
@@ -45,8 +45,8 @@ public class ItemMetadataFilterStage<T> extends AbstractItemMetadataSelectionSta
/** Class logger. */
private final Logger log = LoggerFactory.getLogger(ItemMetadataFilterStage.class);
- /** {@inheritDoc} */
- @Override protected void doExecute(@Nonnull @NonnullElements final Collection<Item<T>> itemCollection,
+ @Override
+ protected void doExecute(@Nonnull @NonnullElements final Collection<Item<T>> itemCollection,
final Item<T> matchingItem,
final Map<Class<? extends ItemMetadata>, List<? extends ItemMetadata>> matchingMetadata)
throws StageProcessingException {
@@ -56,4 +56,4 @@ public class ItemMetadataFilterStage<T> extends AbstractItemMetadataSelectionSta
itemCollection.remove(matchingItem);
}
-}
\ No newline at end of file
+}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemMetadataTerminationStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemMetadataTerminationStage.java
index 65f811c..04fe865 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemMetadataTerminationStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemMetadataTerminationStage.java
@@ -43,8 +43,8 @@ public class ItemMetadataTerminationStage<T> extends AbstractItemMetadataSelecti
/** Class logger. */
private final Logger log = LoggerFactory.getLogger(ItemMetadataTerminationStage.class);
- /** {@inheritDoc} */
- @Override protected void doExecute(@Nonnull @NonnullElements final Collection<Item<T>> itemCollection,
+ @Override
+ protected void doExecute(@Nonnull @NonnullElements final Collection<Item<T>> itemCollection,
final Item<T> matchingItem,
final Map<Class<? extends ItemMetadata>, List<? extends ItemMetadata>> matchingMetadata)
throws TerminationException {
@@ -56,4 +56,4 @@ public class ItemMetadataTerminationStage<T> extends AbstractItemMetadataSelecti
throw new TerminationException("Item " + itemId + " marked with metadata of type "
+ matchingMetadata.keySet());
}
-}
\ No newline at end of file
+}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemOrderingStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemOrderingStage.java
index 00fd3c2..d30b0c2 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemOrderingStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemOrderingStage.java
@@ -20,6 +20,7 @@ package net.shibboleth.metadata.pipeline;
import java.util.Collection;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import net.shibboleth.metadata.Item;
@@ -39,7 +40,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
public class ItemOrderingStage<T> extends AbstractStage<T> {
/** Strategy used to order a collection of Items. The default strategy performs no ordering. */
- @Nonnull
+ @Nonnull @GuardedBy("this")
private ItemOrderingStrategy<T> orderingStrategy = new NoOpItemOrderingStrategy<>();
/**
@@ -47,7 +48,7 @@ public class ItemOrderingStage<T> extends AbstractStage<T> {
*
* @return strategy used to order a collection of Items
*/
- @Nonnull public ItemOrderingStrategy<T> getItemOrderingStrategy() {
+ @Nonnull public final synchronized ItemOrderingStrategy<T> getItemOrderingStrategy() {
return orderingStrategy;
}
@@ -64,7 +65,7 @@ public class ItemOrderingStage<T> extends AbstractStage<T> {
@Override
protected void doExecute(@Nonnull @NonnullElements final Collection<Item<T>> itemCollection)
throws StageProcessingException {
- final var orderedItems = orderingStrategy.order(itemCollection);
+ final var orderedItems = getItemOrderingStrategy().order(itemCollection);
itemCollection.clear();
itemCollection.addAll(orderedItems);
}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemOrderingStrategy.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemOrderingStrategy.java
index ef3b45d..81c409c 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemOrderingStrategy.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ItemOrderingStrategy.java
@@ -21,6 +21,7 @@ import java.util.Collection;
import java.util.List;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.ThreadSafe;
import net.shibboleth.metadata.Item;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
@@ -28,11 +29,16 @@ import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
/**
* A strategy that defines how to order a {@link net.shibboleth.metadata.Item} collection.
+ *
+ * <p>
+ * All implementations of this interface <strong>must</strong> be thread-safe.
+ * </p>
*
* @param <T> type of item to be handled
*
* @since 0.10.0
*/
+ at ThreadSafe
public interface ItemOrderingStrategy<T> {
/**
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 ee16e91..85a42e5 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
@@ -23,10 +23,12 @@ import java.io.OutputStream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import net.shibboleth.metadata.Item;
import net.shibboleth.metadata.ItemSerializer;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -92,9 +94,11 @@ public class MultiOutputSerializationStage<T> extends AbstractIteratingStage<T>
}
/** Strategy used to determine where to serialize the item. */
+ @NonnullAfterInit @GuardedBy("this")
private OutputStrategy<T> outputStrategy;
/** Serializer used to write the collection to the output stream. */
+ @NonnullAfterInit @GuardedBy("this")
private ItemSerializer<T> serializer;
/**
@@ -102,7 +106,7 @@ public class MultiOutputSerializationStage<T> extends AbstractIteratingStage<T>
*
* @return the output strategy function
*/
- @Nullable public OutputStrategy<T> getOutputStrategy() {
+ @Nullable public final synchronized OutputStrategy<T> getOutputStrategy() {
return outputStrategy;
}
@@ -121,7 +125,7 @@ public class MultiOutputSerializationStage<T> extends AbstractIteratingStage<T>
*
* @return serializer used to write item to the output file
*/
- @Nullable public ItemSerializer<T> getSerializer() {
+ @Nullable public final synchronized ItemSerializer<T> getSerializer() {
return serializer;
}
@@ -138,9 +142,9 @@ public class MultiOutputSerializationStage<T> extends AbstractIteratingStage<T>
@Override
protected void doExecute(@Nonnull final Item<T> item)
throws StageProcessingException {
- try (final Destination destination = outputStrategy.getDestination(item);
+ try (final Destination destination = getOutputStrategy().getDestination(item);
final OutputStream stream = destination.getOutputStream()) {
- serializer.serialize(item, stream);
+ getSerializer().serialize(item, stream);
} catch (final IOException e) {
throw new StageProcessingException("Error writing to output location", e);
}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/Pipeline.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/Pipeline.java
index 304d91c..7e10c34 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/Pipeline.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/Pipeline.java
@@ -35,11 +35,15 @@ import net.shibboleth.utilities.java.support.component.InitializableComponent;
* first stage is responsible for populating the collection with an initial set of Items which subsequent stages further
* modify.
*
+ * <p>
* Each pipeline must be initialized, via the {@link #initialize()} method, before use. After a pipeline has been
* initialized it may never be re-initialized. A pipeline is not considered initialized until all of its {@link Stage},
* have been initialized.
+ * </p>
*
+ * <p>
* Pipelines are reusable and threadsafe.
+ * </p>
*
* @param <T> type of item which is processed by this pipeline
*/
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/PipelineCallable.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/PipelineCallable.java
index 3199479..a8539c1 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/PipelineCallable.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/PipelineCallable.java
@@ -21,6 +21,7 @@ import java.util.Collection;
import java.util.concurrent.Callable;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.Immutable;
import net.shibboleth.metadata.Item;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
@@ -34,6 +35,7 @@ import org.slf4j.LoggerFactory;
*
* @param <T> type of the items processed by the pipeline
*/
+ at Immutable
public class PipelineCallable<T> implements Callable<Collection<Item<T>>> {
/** Class logger. */
@@ -65,4 +67,4 @@ public class PipelineCallable<T> implements Callable<Collection<Item<T>>> {
pipeline.execute(itemCollection);
return itemCollection;
}
-}
\ No newline at end of file
+}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/PipelineDemultiplexerStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/PipelineDemultiplexerStage.java
index d09eedd..618bf4b 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/PipelineDemultiplexerStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/PipelineDemultiplexerStage.java
@@ -27,6 +27,7 @@ import java.util.function.Predicate;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import net.shibboleth.metadata.Item;
@@ -61,6 +62,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
public class PipelineDemultiplexerStage<T> extends AbstractStage<T> {
/** Service used to execute the selected and/or non-selected item pipelines. */
+ @Nonnull @GuardedBy("this")
private ExecutorService executorService = Executors.newSingleThreadExecutor();
/**
@@ -68,13 +70,14 @@ public class PipelineDemultiplexerStage<T> extends AbstractStage<T> {
*
* Default: <code>true</code>.
*/
- private boolean waitingForPipelines = true;
+ @GuardedBy("this") private boolean waitingForPipelines = true;
/** Factory used to create the Item collection that is then given to the pipelines. */
+ @Nonnull @GuardedBy("this")
private Supplier<Collection<Item<T>>> collectionFactory = new SimpleItemCollectionFactory<>();
/** The pipelines through which items are sent and the selection strategy used for that pipeline. */
- @Nonnull @NonnullElements @Unmodifiable
+ @Nonnull @NonnullElements @Unmodifiable @GuardedBy("this")
private List<Pair<Pipeline<T>, Predicate<Item<T>>>> pipelineAndStrategies = List.of();
/**
@@ -82,7 +85,7 @@ public class PipelineDemultiplexerStage<T> extends AbstractStage<T> {
*
* @return executor service used to run the selected and non-selected item pipelines
*/
- @Nonnull public ExecutorService getExecutorService() {
+ @Nonnull public final synchronized ExecutorService getExecutorService() {
return executorService;
}
@@ -101,7 +104,7 @@ public class PipelineDemultiplexerStage<T> extends AbstractStage<T> {
*
* @return whether this child waits for all the invoked pipelines to complete before proceeding
*/
- public boolean isWaitingForPipelines() {
+ public final synchronized boolean isWaitingForPipelines() {
return waitingForPipelines;
}
@@ -120,7 +123,7 @@ public class PipelineDemultiplexerStage<T> extends AbstractStage<T> {
*
* @return factory used to create the Item collection that is then given to the pipelines
*/
- @Nonnull public Supplier<Collection<Item<T>>> getCollectionFactory() {
+ @Nonnull public final synchronized Supplier<Collection<Item<T>>> getCollectionFactory() {
return collectionFactory;
}
@@ -139,7 +142,7 @@ public class PipelineDemultiplexerStage<T> extends AbstractStage<T> {
*
* @return pipeline and item selection strategies used to demultiplex item collections within this stage
*/
- @Nonnull @NonnullElements @Unmodifiable public List<Pair<Pipeline<T>, Predicate<Item<T>>>>
+ @Nonnull @NonnullElements @Unmodifiable public final synchronized List<Pair<Pipeline<T>, Predicate<Item<T>>>>
getPipelineAndSelectionStrategies() {
return pipelineAndStrategies;
}
@@ -166,10 +169,10 @@ public class PipelineDemultiplexerStage<T> extends AbstractStage<T> {
throws StageProcessingException {
final ArrayList<Future<Collection<Item<T>>>> pipelineFutures = new ArrayList<>();
- for (final Pair<Pipeline<T>, Predicate<Item<T>>> pipelineAndStrategy : pipelineAndStrategies) {
+ for (final Pair<Pipeline<T>, Predicate<Item<T>>> pipelineAndStrategy : getPipelineAndSelectionStrategies()) {
final Pipeline<T> pipeline = pipelineAndStrategy.getFirst();
final Predicate<Item<T>> selectionStrategy = pipelineAndStrategy.getSecond();
- final Collection<Item<T>> selectedItems = collectionFactory.get();
+ final Collection<Item<T>> selectedItems = getCollectionFactory().get();
for (final Item<T> item : itemCollection) {
if (selectionStrategy.test(item)) {
@@ -179,7 +182,7 @@ public class PipelineDemultiplexerStage<T> extends AbstractStage<T> {
}
}
- pipelineFutures.add(executorService.submit(new PipelineCallable<>(pipeline, selectedItems)));
+ pipelineFutures.add(getExecutorService().submit(new PipelineCallable<>(pipeline, selectedItems)));
}
if (isWaitingForPipelines()) {
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/PipelineMergeStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/PipelineMergeStage.java
index aaac44e..b49fede 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/PipelineMergeStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/PipelineMergeStage.java
@@ -26,6 +26,7 @@ import java.util.concurrent.Future;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import net.shibboleth.metadata.CollectionMergeStrategy;
@@ -52,19 +53,22 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
public class PipelineMergeStage<T> extends AbstractStage<T> {
/** Service used to execute the pipelines whose results will be merged. */
+ @Nonnull @GuardedBy("this")
private ExecutorService executorService = Executors.newSingleThreadExecutor();
/**
* The factory used to create the item returned by this source. Default implementation is
* {@link SimpleItemCollectionFactory}.
*/
+ @Nonnull @GuardedBy("this")
private Supplier<Collection<Item<T>>> collectionFactory = new SimpleItemCollectionFactory<>();
/** Strategy used to merge all the joined pipeline results in to the final Item collection. */
+ @Nonnull @GuardedBy("this")
private CollectionMergeStrategy mergeStrategy = new SimpleCollectionMergeStrategy();
/** Pipelines whose results become the output of this source. */
- @Nonnull @NonnullElements @Unmodifiable
+ @Nonnull @NonnullElements @Unmodifiable @GuardedBy("this")
private List<Pipeline<T>> mergedPipelines = List.of();
/**
@@ -72,7 +76,7 @@ public class PipelineMergeStage<T> extends AbstractStage<T> {
*
* @return executor service used to run the selected and non-selected item pipelines
*/
- @Nonnull public ExecutorService getExecutorService() {
+ @Nonnull public final synchronized ExecutorService getExecutorService() {
return executorService;
}
@@ -92,7 +96,7 @@ public class PipelineMergeStage<T> extends AbstractStage<T> {
* @return unmodifiable set of pipelines used by this stage
*/
@Nonnull @NonnullElements @Unmodifiable
- public List<Pipeline<T>> getMergedPipelines() {
+ public final synchronized List<Pipeline<T>> getMergedPipelines() {
return mergedPipelines;
}
@@ -112,7 +116,7 @@ public class PipelineMergeStage<T> extends AbstractStage<T> {
*
* @return factory used to create the {@link Item} collection produced by this source
*/
- @Nonnull public Supplier<Collection<Item<T>>> getCollectionFactory() {
+ @Nonnull public final synchronized Supplier<Collection<Item<T>>> getCollectionFactory() {
return collectionFactory;
}
@@ -131,7 +135,7 @@ public class PipelineMergeStage<T> extends AbstractStage<T> {
*
* @return strategy used to merge all the joined pipeline results in to the final Item collection, never null
*/
- @Nonnull public CollectionMergeStrategy getCollectionMergeStrategy() {
+ @Nonnull public final synchronized CollectionMergeStrategy getCollectionMergeStrategy() {
return mergeStrategy;
}
@@ -151,9 +155,9 @@ public class PipelineMergeStage<T> extends AbstractStage<T> {
throws StageProcessingException {
final ArrayList<Future<Collection<Item<T>>>> pipelineResultFutures = new ArrayList<>();
- for (final Pipeline<T> pipeline : mergedPipelines) {
- pipelineResultFutures.add(executorService.submit(
- new PipelineCallable<>(pipeline, collectionFactory.get())));
+ for (final Pipeline<T> pipeline : getMergedPipelines()) {
+ pipelineResultFutures.add(getExecutorService().submit(
+ new PipelineCallable<>(pipeline, getCollectionFactory().get())));
}
final ArrayList<Collection<Item<T>>> pipelineResults = new ArrayList<>();
@@ -161,7 +165,7 @@ public class PipelineMergeStage<T> extends AbstractStage<T> {
pipelineResults.add(FutureSupport.futureItems(future));
}
- mergeStrategy.mergeCollection(itemCollection, pipelineResults);
+ getCollectionMergeStrategy().mergeCollection(itemCollection, pipelineResults);
}
@Override
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ScriptletStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ScriptletStage.java
index bc61d7a..ac9500e 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ScriptletStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/ScriptletStage.java
@@ -21,6 +21,7 @@ import java.util.Collection;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import javax.script.ScriptException;
import javax.script.SimpleScriptContext;
@@ -29,6 +30,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.shibboleth.metadata.Item;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -60,6 +62,7 @@ public class ScriptletStage<T> extends AbstractStage<T> {
private final Logger log = LoggerFactory.getLogger(ScriptletStage.class);
/** Script executed by this stage. */
+ @NonnullAfterInit @GuardedBy("this")
private EvaluableScript script;
/**
@@ -67,7 +70,7 @@ public class ScriptletStage<T> extends AbstractStage<T> {
*
* @return the script executed by this stage
*/
- @Nullable public EvaluableScript getScript() {
+ @Nullable public final synchronized EvaluableScript getScript() {
return script;
}
@@ -81,14 +84,14 @@ public class ScriptletStage<T> extends AbstractStage<T> {
script = Constraint.isNotNull(stageScript, "Stage script can not be null");
}
- /** {@inheritDoc} */
- @Override protected void doExecute(@Nonnull @NonnullElements final Collection<Item<T>> itemCollection)
+ @Override
+ protected void doExecute(@Nonnull @NonnullElements final Collection<Item<T>> itemCollection)
throws StageProcessingException {
final SimpleScriptContext context = new SimpleScriptContext();
context.setAttribute(ITEMS, itemCollection, SimpleScriptContext.ENGINE_SCOPE);
try {
- script.eval(context);
+ getScript().eval(context);
} catch (final ScriptException e) {
final String errMsg = getId() + " pipeline stage unable to execute script";
log.error(errMsg, e);
@@ -96,12 +99,12 @@ public class ScriptletStage<T> extends AbstractStage<T> {
}
}
- /** {@inheritDoc} */
- @Override protected void doInitialize() throws ComponentInitializationException {
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
super.doInitialize();
if (script == null) {
throw new ComponentInitializationException("Unable to initialize " + getId() + ", script may not be null");
}
}
-}
\ No newline at end of file
+}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/SerializationStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/SerializationStage.java
index 0db44ca..e693073 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/SerializationStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/SerializationStage.java
@@ -25,6 +25,7 @@ import java.util.Collection;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import org.slf4j.Logger;
@@ -57,13 +58,14 @@ public class SerializationStage<T> extends AbstractStage<T> {
private final Logger log = LoggerFactory.getLogger(SerializationStage.class);
/** File to which the item will be written. */
- @NonnullAfterInit
+ @NonnullAfterInit @GuardedBy("this")
private File outputFile;
/** Whether an existing output file should be overwritten. Default value: <code>true</code> */
- private boolean overwritingExistingOutputFile = true;
+ @GuardedBy("this") private boolean overwritingExistingOutputFile = true;
/** Serializer used to write the collection to the output stream. */
+ @NonnullAfterInit @GuardedBy("this")
private ItemCollectionSerializer<T> serializer;
/**
@@ -71,7 +73,7 @@ public class SerializationStage<T> extends AbstractStage<T> {
*
* @return file to which the item will be written
*/
- @NonnullAfterInit public File getOutputFile() {
+ @NonnullAfterInit public final synchronized File getOutputFile() {
return outputFile;
}
@@ -90,7 +92,7 @@ public class SerializationStage<T> extends AbstractStage<T> {
*
* @return whether an existing output file should be overwritten
*/
- public boolean isOverwritingExistingOutputFile() {
+ public final synchronized boolean isOverwritingExistingOutputFile() {
return overwritingExistingOutputFile;
}
@@ -109,7 +111,7 @@ public class SerializationStage<T> extends AbstractStage<T> {
*
* @return serializer used to write item to the output file
*/
- @Nullable public ItemCollectionSerializer<T> getSerializer() {
+ @Nullable public final synchronized ItemCollectionSerializer<T> getSerializer() {
return serializer;
}
@@ -123,26 +125,27 @@ public class SerializationStage<T> extends AbstractStage<T> {
serializer = Constraint.isNotNull(itemSerializer, "Item collection serializer can not be null");
}
- /** {@inheritDoc} */
- @Override protected void doExecute(@Nonnull @NonnullElements final Collection<Item<T>> itemCollection)
+ @Override
+ protected void doExecute(@Nonnull @NonnullElements final Collection<Item<T>> itemCollection)
throws StageProcessingException {
- try (OutputStream stream = new FileOutputStream(outputFile)) {
- serializer.serializeCollection(itemCollection, stream);
+ try (OutputStream stream = new FileOutputStream(getOutputFile())) {
+ getSerializer().serializeCollection(itemCollection, stream);
} catch (final IOException e) {
- throw new StageProcessingException("Error writing to output file " + outputFile.getAbsolutePath(), e);
+ throw new StageProcessingException("Error writing to output file " +
+ getOutputFile().getAbsolutePath(), e);
}
}
- /** {@inheritDoc} */
- @Override protected void doDestroy() {
+ @Override
+ protected void doDestroy() {
outputFile = null;
serializer = null;
super.doDestroy();
}
- /** {@inheritDoc} */
- @Override protected void doInitialize() throws ComponentInitializationException {
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
super.doInitialize();
if (outputFile == null) {
@@ -181,4 +184,4 @@ public class SerializationStage<T> extends AbstractStage<T> {
}
}
-}
\ No newline at end of file
+}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/SplitMergeStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/SplitMergeStage.java
index a5626f9..0752cb9 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/SplitMergeStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/SplitMergeStage.java
@@ -27,6 +27,7 @@ import java.util.function.Supplier;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import org.slf4j.Logger;
@@ -69,21 +70,27 @@ public class SplitMergeStage<T> extends AbstractStage<T> {
private final Logger log = LoggerFactory.getLogger(SplitMergeStage.class);
/** Service used to execute the selected and/or non-selected item pipelines. */
+ @Nonnull @GuardedBy("this")
private ExecutorService executorService = Executors.newSingleThreadExecutor();
/** Factory used to create the Item collection that is then given to the pipelines. */
+ @Nonnull @GuardedBy("this")
private Supplier<Collection<Item<T>>> collectionFactory = new SimpleItemCollectionFactory<>();
/** Strategy used to split the given item collection. */
+ @Nonnull @GuardedBy("this")
private Predicate<Item<T>> selectionStrategy = x -> false;
/** Pipeline that receives the selected items. */
+ @Nullable @GuardedBy("this")
private Pipeline<T> selectedItemPipeline;
/** Pipeline that receives the non-selected items. */
+ @Nullable @GuardedBy("this")
private Pipeline<T> nonselectedItemPipeline;
/** Strategy used to merge all the joined pipeline results in to the final Item collection. */
+ @Nonnull @GuardedBy("this")
private CollectionMergeStrategy mergeStrategy = new SimpleCollectionMergeStrategy();
/**
@@ -91,7 +98,7 @@ public class SplitMergeStage<T> extends AbstractStage<T> {
*
* @return executor service used to run the selected and non-selected item pipelines
*/
- @Nonnull public ExecutorService getExecutorService() {
+ @Nonnull public final synchronized ExecutorService getExecutorService() {
return executorService;
}
@@ -110,7 +117,7 @@ public class SplitMergeStage<T> extends AbstractStage<T> {
*
* @return factory used to create the Item collection that is then given to the pipelines
*/
- @Nonnull public Supplier<Collection<Item<T>>> getCollectionFactory() {
+ @Nonnull public final synchronized Supplier<Collection<Item<T>>> getCollectionFactory() {
return collectionFactory;
}
@@ -129,7 +136,7 @@ public class SplitMergeStage<T> extends AbstractStage<T> {
*
* @return strategy used to split the given item collection
*/
- @Nonnull public Predicate<Item<T>> getSelectionStrategy() {
+ @Nonnull public final synchronized Predicate<Item<T>> getSelectionStrategy() {
return selectionStrategy;
}
@@ -148,7 +155,7 @@ public class SplitMergeStage<T> extends AbstractStage<T> {
*
* @return pipeline that receives the selected items
*/
- @Nullable public Pipeline<T> getSelectedItemPipeline() {
+ @Nullable public final synchronized Pipeline<T> getSelectedItemPipeline() {
return selectedItemPipeline;
}
@@ -167,7 +174,7 @@ public class SplitMergeStage<T> extends AbstractStage<T> {
*
* @return pipeline that receives the non-selected items
*/
- @Nullable public Pipeline<T> getNonselectedItemPipeline() {
+ @Nullable public final synchronized Pipeline<T> getNonselectedItemPipeline() {
return nonselectedItemPipeline;
}
@@ -186,7 +193,7 @@ public class SplitMergeStage<T> extends AbstractStage<T> {
*
* @return strategy used to merge all the joined pipeline results in to the final Item collection, never null
*/
- @Nonnull public CollectionMergeStrategy getCollectionMergeStrategy() {
+ @Nonnull public final synchronized CollectionMergeStrategy getCollectionMergeStrategy() {
return mergeStrategy;
}
@@ -201,27 +208,25 @@ public class SplitMergeStage<T> extends AbstractStage<T> {
mergeStrategy = Constraint.isNotNull(strategy, "Collection merge strategy can not be null");
}
- /** {@inheritDoc} */
- @Override protected void doExecute(@Nonnull @NonnullElements final Collection<Item<T>> itemCollection)
+ @Override
+ protected void doExecute(@Nonnull @NonnullElements final Collection<Item<T>> itemCollection)
throws StageProcessingException {
- final Collection<Item<T>> selectedItems = collectionFactory.get();
- final Collection<Item<T>> nonselectedItems = collectionFactory.get();
+ final Collection<Item<T>> selectedItems = getCollectionFactory().get();
+ final Collection<Item<T>> nonselectedItems = getCollectionFactory().get();
+ final var strategy = getSelectionStrategy();
for (final Item<T> item : itemCollection) {
- if (item == null) {
- continue;
- }
-
- if (selectionStrategy.test(item)) {
+ if (strategy.test(item)) {
selectedItems.add(item);
} else {
nonselectedItems.add(item);
}
}
- final Future<Collection<Item<T>>> selectedItemFuture = executePipeline(selectedItemPipeline, selectedItems);
+ final Future<Collection<Item<T>>> selectedItemFuture =
+ executePipeline(getSelectedItemPipeline(), selectedItems);
final Future<Collection<Item<T>>> nonselectedItemFuture =
- executePipeline(nonselectedItemPipeline, nonselectedItems);
+ executePipeline(getNonselectedItemPipeline(), nonselectedItems);
final ArrayList<Collection<Item<T>>> pipelineResults = new ArrayList<>();
@@ -230,7 +235,7 @@ public class SplitMergeStage<T> extends AbstractStage<T> {
pipelineResults.add(FutureSupport.futureItems(nonselectedItemFuture));
itemCollection.clear();
- mergeStrategy.mergeCollection(itemCollection, pipelineResults);
+ getCollectionMergeStrategy().mergeCollection(itemCollection, pipelineResults);
}
/**
@@ -253,11 +258,11 @@ public class SplitMergeStage<T> extends AbstractStage<T> {
}
final PipelineCallable<T> callable = new PipelineCallable<>(pipeline, items);
- return executorService.submit(callable);
+ return getExecutorService().submit(callable);
}
- /** {@inheritDoc} */
- @Override protected void doDestroy() {
+ @Override
+ protected void doDestroy() {
executorService = null;
collectionFactory = null;
selectionStrategy = null;
@@ -268,8 +273,8 @@ public class SplitMergeStage<T> extends AbstractStage<T> {
super.doDestroy();
}
- /** {@inheritDoc} */
- @Override protected void doInitialize() throws ComponentInitializationException {
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
super.doInitialize();
if (selectedItemPipeline == null && nonselectedItemPipeline == null) {
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/Stage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/Stage.java
index a46f548..b85df67 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/Stage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/Stage.java
@@ -31,8 +31,10 @@ import net.shibboleth.utilities.java.support.component.InitializableComponent;
/**
* A stage in a {@link Pipeline} that operates upon a collection {@link Item} in a particular manner.
*
+ * <p>
* Stages must be thread safe and reusable.
- *
+ * </p>
+ *
* @param <T> type of metadata upon which the stage operates
*/
@ThreadSafe
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/StaticItemSourceStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/StaticItemSourceStage.java
index 420ae62..140e33d 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/StaticItemSourceStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/StaticItemSourceStage.java
@@ -21,6 +21,7 @@ import java.util.Collection;
import java.util.List;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import net.shibboleth.metadata.Item;
@@ -36,7 +37,7 @@ import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
public class StaticItemSourceStage<T> extends AbstractStage<T> {
/** Collection of static Items added to each Item collection by {@link #execute(Collection)}. */
- @Nonnull @NonnullElements @Unmodifiable
+ @Nonnull @NonnullElements @Unmodifiable @GuardedBy("this")
private List<Item<T>> source = List.of();
/**
@@ -45,7 +46,7 @@ public class StaticItemSourceStage<T> extends AbstractStage<T> {
* @return collection of static Items added to the Item collection by this stage
*/
@Nonnull @NonnullElements @Unmodifiable
- public Collection<Item<T>> getSourceItems() {
+ public final synchronized Collection<Item<T>> getSourceItems() {
return source;
}
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/StatusMetadataLoggingStage.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/StatusMetadataLoggingStage.java
index 7f2b09b..b158452 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/StatusMetadataLoggingStage.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/StatusMetadataLoggingStage.java
@@ -46,12 +46,12 @@ public class StatusMetadataLoggingStage<T> extends AbstractItemMetadataSelection
/** Class logger. */
private final Logger log = LoggerFactory.getLogger(StatusMetadataLoggingStage.class);
- /** {@inheritDoc} */
- @Override protected void doExecute(
- @Nonnull @NonnullElements final Collection<Item<T>> itemCollection,
- @Nonnull final Item<T> matchingItem,
- @Nonnull @NonnullElements final Map<Class<? extends ItemMetadata>,
- List<? extends ItemMetadata>> matchingMetadata)
+ @Override
+ protected void doExecute(
+ @Nonnull @NonnullElements final Collection<Item<T>> itemCollection,
+ @Nonnull final Item<T> matchingItem,
+ @Nonnull @NonnullElements final Map<Class<? extends ItemMetadata>,
+ List<? extends ItemMetadata>> matchingMetadata)
throws StageProcessingException {
final String itemId = getItemIdentificationStrategy().getItemIdentifier(matchingItem);
diff --git a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/impl/NoOpItemOrderingStrategy.java b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/impl/NoOpItemOrderingStrategy.java
index 4856753..7f667b3 100644
--- a/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/impl/NoOpItemOrderingStrategy.java
+++ b/aggregator-pipeline/src/main/java/net/shibboleth/metadata/pipeline/impl/NoOpItemOrderingStrategy.java
@@ -21,6 +21,7 @@ import java.util.Collection;
import java.util.List;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.Immutable;
import net.shibboleth.metadata.Item;
import net.shibboleth.metadata.pipeline.ItemOrderingStrategy;
@@ -34,6 +35,7 @@ import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
*
* @since 0.10.0
*/
+ at Immutable
public class NoOpItemOrderingStrategy<T> implements ItemOrderingStrategy<T> {
@Override
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list