Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add InCommonEntityOrderingStrategy
Initial implementation and basic test.
See incommon/inc-meta#55.
iay committed Mar 25, 2017
1 parent e903af1 commit d069d1d
Showing 7 changed files with 285 additions and 15 deletions.
4 changes: 2 additions & 2 deletions .checkstyle
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>

<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false">
<fileset-config file-format-version="1.2.0" simple-config="false" sync-formatter="false">
<local-check-config name="Shibboleth" location="/Users/iay/git/github/ukf/ukf-mda/checkstyle.xml" type="external" description="Variant of Shibboleth checkstyle.xml">
<additional-data name="protect-config-file" value="false"/>
</local-check-config>
<fileset name="all" enabled="true" check-config-name="Shibboleth" local="true">
<file-match-pattern match-pattern="." include-pattern="true"/>
<file-match-pattern match-pattern="src/main/java/" include-pattern="true"/>
</fileset>
</fileset-config>
1 change: 1 addition & 0 deletions .gitignore
@@ -1 +1,2 @@
/target/
/test-output/
4 changes: 2 additions & 2 deletions .project
@@ -16,12 +16,12 @@
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
30 changes: 19 additions & 11 deletions pom.xml
@@ -22,6 +22,7 @@

<properties>
<mda.version>0.9.2</mda.version>
<ukf-mda.version>0.9.4</ukf-mda.version>
<java-support.version>7.2.0</java-support.version>
<checkstyle.version>7.6</checkstyle.version>
</properties>
@@ -41,6 +42,20 @@
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>ukf-release</id>
<url>https://apps.iay.org.uk/nexus/content/repositories/ukf</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>ukf-snapshot</id>
<url>https://apps.iay.org.uk/nexus/content/repositories/ukf-snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>

<dependencies>
@@ -51,10 +66,6 @@
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>net.shibboleth.metadata</groupId>
<artifactId>aggregator-pipeline</artifactId>
@@ -73,13 +84,10 @@
<!-- Test dependencies -->

<dependency>
<groupId>${spring.groupId}</groupId>
<artifactId>spring-context</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${spring.groupId}</groupId>
<artifactId>spring-test</artifactId>
<groupId>uk.org.ukfederation</groupId>
<artifactId>ukf-mda</artifactId>
<version>${ukf-mda.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>

@@ -0,0 +1,179 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package uk.org.iay.incommon.dom.saml;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.ThreadSafe;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;

import net.shibboleth.metadata.Item;
import net.shibboleth.metadata.ItemId;
import net.shibboleth.metadata.dom.saml.EntitiesDescriptorAssemblerStage.ItemOrderingStrategy;
import net.shibboleth.metadata.dom.saml.mdrpi.RegistrationAuthority;
import net.shibboleth.metadata.pipeline.StageProcessingException;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;

/**
* Implements an ordering strategy for InCommon federation aggregates.
*
* The input list contains entities registered by InCommon in a specific
* order which must not be disturbed. They are followed by entities registered
* elsewhere; these are to be grouped by registrar and then within registrar
* ordered by entityID.
*
* The registrar and entityID values used for ordering are required to be
* present in the item's item metadata.
*/
@ThreadSafe
public class InCommonEntityOrderingStrategy implements ItemOrderingStrategy {

/** Class logger. */
private final Logger log = LoggerFactory.getLogger(InCommonEntityOrderingStrategy.class);

/** The registrar whose entities should always appear first, in the provided order. */
private final String distinguishedRegistrar;

/**
* Helper class which wraps an {@link Element} {@link Item} but extracts any
* associated {@link RegistrationAuthority} and {@link ItemId} for simpler comparisons.
*/
private static class OrderableItem implements Comparable<OrderableItem> {

/** The wrapped {@link Element} {@link Item}. */
private final Item<Element> item;

/** The registrar for this entity. */
private final String registrar;

/** The entityID for this entity. */
private final String entityID;

/**
* Constructor.
*
* @param domItem the {@link Element} {@link Item} to wrap
* @param reg the registrar for this entity
* @param entity the entityID for this entity
*/
public OrderableItem(@Nonnull final Item<Element> domItem,
@Nonnull final String reg, @Nonnull final String entity) {
item = domItem;
registrar = reg;
entityID = entity;
}

@Override
public int compareTo(@Nonnull final OrderableItem o) {
// compare registrar values
final int c = registrar.compareTo(o.registrar);
// done if unequal
if (c != 0) {
return c;
}
// compare entityID values if registrars equal
return entityID.compareTo(o.entityID);
}

/**
* Unwrap the wrapped {@link Element} {@link Item}.
*
* @return the wrapped {@link Element} {@link Item}.
*/
public Item<Element> unwrap() {
return item;
}
}

/**
* Constructor.
*
* @param registrar distinguished registrar, whose entities sort first
*/
public InCommonEntityOrderingStrategy(@Nonnull final String registrar) {
distinguishedRegistrar = registrar;
}

@Override
public List<Item<Element>> order(@Nonnull @NonnullElements final Collection<Item<Element>> items) {

// Collect the results here
final List<Item<Element>> results = new ArrayList<>(items.size());

/*
* Construct an orderable list wrapping the original items.
*
* Any belonging to the distinguished registrar are instead put straight in the
* results list.
*/
final List<OrderableItem> orderableList = new ArrayList<>(items.size());
try {
for (Item<Element> item : items) {
final List<RegistrationAuthority> registrars = item.getItemMetadata().get(RegistrationAuthority.class);
final String registrar;
if (registrars.size() == 0) {
throw new StageProcessingException("entity does not have RegistrationAuthority item metadata");
} else {
registrar = registrars.get(0).getRegistrationAuthority();
if (distinguishedRegistrar.equals(registrar)) {
results.add(item);
continue;
}
}

final List<ItemId> itemids = item.getItemMetadata().get(ItemId.class);
final String entityID;
if (itemids.size() == 0) {
throw new StageProcessingException("entity does not have ItemId item metadata");
} else {
entityID = itemids.get(0).getId();
}

orderableList.add(new OrderableItem(item, registrar, entityID));
}
} catch (StageProcessingException e) {
/*
* If the ordering operation fails because we can't create an OrderableItem
* for each original item, it's probably because we are missing some item
* metadata on one or more items. The signature for the order method does
* not allow this to be reported as of MDA 0.9.x.
*
* This will change in MDA 0.10.0 (see IDP-175) but for now all we
* can really do is log an error and return the items in their
* original order.
*/
log.error("could not order entities because of lack of entity metadata; returning original ordering");
return new ArrayList<>(items);
}

// sort the orderable list
Collections.sort(orderableList);

// Add the ordered results into the results collection
for (OrderableItem result : orderableList) {
results.add(result.unwrap());
}

return results;
}

}
@@ -0,0 +1,78 @@

package uk.org.iay.incommon.dom.saml;

import java.util.ArrayList;
import java.util.List;

import org.testng.Assert;
import org.testng.annotations.Test;
import org.w3c.dom.Element;

import net.shibboleth.metadata.Item;
import net.shibboleth.metadata.ItemId;
import net.shibboleth.metadata.dom.DOMElementItem;
import net.shibboleth.metadata.dom.saml.mdrpi.RegistrationAuthority;
import uk.org.ukfederation.mda.BaseDOMTest;

public class InCommonEntityOrderingStrategyTest extends BaseDOMTest {

protected InCommonEntityOrderingStrategyTest() {
super(InCommonEntityOrderingStrategy.class);
}

private Item<Element> makeItem(String registrar, String entityID) throws Exception {
final Item<Element> item = new DOMElementItem(readXmlData("trivial.xml"));
item.getItemMetadata().put(new ItemId(entityID));
item.getItemMetadata().put(new RegistrationAuthority(registrar));
return item;
}

@Test
public void testOrder() throws Exception {
// distinguished registrar
final String registrar_d = "http://d";

// other registrars
final String registrar_1 = "http://registrar1";
final String registrar_2 = "http://registrar2";

// create some items in the order they will end up
final Item<Element> i00 = makeItem(registrar_d, "entity-id-999");
final Item<Element> i01 = makeItem(registrar_d, "entity-id-777");
final Item<Element> i10 = makeItem(registrar_1, "entity-id-0");
final Item<Element> i11 = makeItem(registrar_1, "entity-id-5");
final Item<Element> i12 = makeItem(registrar_1, "entity-id-9");
final Item<Element> i20 = makeItem(registrar_2, "entity-id-a");
final Item<Element> i21 = makeItem(registrar_2, "entity-id-m");
final Item<Element> i22 = makeItem(registrar_2, "entity-id-z");

// Make a collection containing those items in an arbitrary order
// Note that the registrar_d items must be in the final order
final List<Item<Element>> items = new ArrayList<>();
items.add(i22);
items.add(i11);
items.add(i00);
items.add(i12);
items.add(i20);
items.add(i21);
items.add(i01);
items.add(i10);
Assert.assertEquals(items.size(), 8);

// Order the collection
final InCommonEntityOrderingStrategy strat = new InCommonEntityOrderingStrategy(registrar_d);
final List<Item<Element>>items2 = strat.order(items);

// Check that everything is in the right place afterwards
Assert.assertEquals(items2.size(), items.size());
Assert.assertEquals(items2.get(0), i00, "i00");
Assert.assertEquals(items2.get(1), i01, "i01");
Assert.assertEquals(items2.get(2), i10, "i10");
Assert.assertEquals(items2.get(3), i11, "i11");
Assert.assertEquals(items2.get(4), i12, "i12");
Assert.assertEquals(items2.get(5), i20, "i20");
Assert.assertEquals(items2.get(6), i21, "i21");
Assert.assertEquals(items2.get(7), i22, "i22");
}

}
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<trivial>
<!-- nothing here, really -->
</trivial>

0 comments on commit d069d1d

Please sign in to comment.