[java-shib-shared] branch main updated: Phase 2 of refactor

Scott Cantor cantor.2 at osu.edu
Thu Sep 1 18:05:50 UTC 2022


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

scantor pushed a commit to branch main
in repository java-shib-shared.

View the commit online:
http://git.shibboleth.net/view/?p=java-shib-shared.git;a=commit;h=291db598ef4988d4e8264db9ea566b2b3b31d91f

The following commit(s) were added to refs/heads/main by this push:
     new 291db598 Phase 2 of refactor
291db598 is described below

commit 291db598ef4988d4e8264db9ea566b2b3b31d91f
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Sep 1 14:05:47 2022 -0400

    Phase 2 of refactor
    
    - Move out DDF code into SP
    - Create velocity and service modules
    - Eliminate use of testing module in spring-exts
---
 pom.xml                                            |    2 +
 shib-networking/pom.xml                            |   28 +-
 .../shibboleth/utilities/java/support/ddf/DDF.java | 1602 --------------------
 .../utilities/java/support/ddf/DDFSupport.java     |  101 --
 .../support/ddf/RemotedHttpServletRequest.java     |  688 ---------
 .../support/ddf/RemotedHttpServletResponse.java    |  504 ------
 .../utilities/java/support/ddf/DDFSupportTest.java |   96 --
 .../utilities/java/support/ddf/DDFTest.java        |  480 ------
 .../support/ddf/RemotedHttpServletRequestTest.java |  171 ---
 .../ddf/RemotedHttpServletResponseTest.java        |  143 --
 shib-security/pom.xml                              |   37 +-
 .../security/impl/BasicAccessControlService.java   |    1 -
 .../impl/BasicKeystoreKeyStrategyTest.java         |    1 -
 shib-service/.check-m2                             |    1 +
 shib-service/.checkstyle                           |   15 +
 shib-service/.gitignore                            |   21 +
 {shib-networking => shib-service}/pom.xml          |   58 +-
 .../service/AbstractServiceableComponent.java      |    0
 .../service/ApplicationContextServiceStrategy.java |    0
 .../ApplicationContextServiceableComponent.java    |    0
 .../spring/service/ClassBasedServiceStrategy.java  |    0
 .../spring/service/ReloadableSpringService.java    |    0
 .../ext/spring/service/package-info.java           |    0
 .../shibboleth/shared}/service/LoggingService.java |    3 +-
 .../service/impl}/LogbackLoggingService.java       |    4 +-
 .../shared/service/impl}/package-info.java         |   11 +-
 .../shibboleth/shared/service}/package-info.java   |    7 +-
 .../service/reloadable}/NonReloadableExcluder.java |    2 +-
 .../service/reloadable}/ProxiedFactoryBean.java    |    2 +-
 .../service/reloadable}/ReloadableScope.java       |    2 +-
 .../shared/service/reloadable}/package-info.java   |    7 +-
 .../impl/DelegatingAccessControlService.java       |    2 +-
 .../impl/ReloadingAccessControlService.java        |    7 +-
 .../impl}/ServiceableAccessControlService.java     |    3 +-
 .../service/security/impl}/package-info.java       |    7 +-
 .../support/service/AbstractReloadableService.java |    0
 .../java/support/service/ReloadableService.java    |    0
 .../support/service/ReloadableServiceGaugeSet.java |    0
 .../java/support/service/ServiceException.java     |    0
 .../java/support/service/ServiceableComponent.java |    0
 .../java/support/service/package-info.java         |    0
 .../ext/spring/service/NonReloadableTestBean.java  |    0
 .../spring/service/ReloadableBeanServiceTest.java  |    0
 .../service/ReloadableSpringServiceTest.java       |    0
 .../ext/spring/service/ReloadableTestBean.java     |    0
 .../spring/service/TestServiceableComponent.java   |    0
 .../shibboleth/ext/spring/service/BrokenBean1.xml  |    0
 .../shibboleth/ext/spring/service/BrokenBean2.xml  |    0
 .../ext/spring/service/ReloadableBeans1.xml        |    4 +-
 .../ext/spring/service/ReloadableSpringService.xml |    0
 .../ext/spring/service/ServiceableBean1.xml        |    0
 .../ext/spring/service/ServiceableBean2.xml        |    0
 shib-shared-bom/pom.xml                            |   12 +-
 shib-spring/pom.xml                                |   32 +-
 .../ext/spring/config/ByteArrayToDDFConverter.java |   43 -
 .../ext/spring/config/DDFToByteArrayConverter.java |   43 -
 .../spring/resource/ConditionalResourceTest.java   |    2 -
 .../resource/FileBackedHTTPResourceTest.java       |    1 -
 .../ext/spring/resource/HTTPResourceTest.java      |    1 -
 .../ext/spring/resource}/RepositorySupport.java    |    8 +-
 .../ext/spring/resource}/ResourceTestHelper.java   |    6 +-
 shib-support/pom.xml                               |   31 +-
 shib-testing/pom.xml                               |   12 +
 .../java/support/testing/RepositorySupport.java    |    6 +-
 .../java/support/testing/ResourceTestHelper.java   |    4 +-
 .../support/testing/RepositorySupportTest.java     |    2 -
 shib-velocity/.check-m2                            |    1 +
 shib-velocity/.checkstyle                          |   15 +
 shib-velocity/.gitignore                           |   21 +
 {shib-testing => shib-velocity}/pom.xml            |   27 +-
 .../utilities/java/support/velocity/Template.java  |    0
 .../java/support/velocity/package-info.java        |    0
 72 files changed, 242 insertions(+), 4035 deletions(-)

diff --git a/pom.xml b/pom.xml
index 48da6876..b203f4a4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,7 +29,9 @@
         <module>shib-spring</module>
         <module>shib-networking</module>
         <module>shib-security</module>
+        <module>shib-service</module>
         <module>shib-testing</module>
+        <module>shib-velocity</module>
     </modules>
 
     <properties>
diff --git a/shib-networking/pom.xml b/shib-networking/pom.xml
index c23fcc90..640f1dae 100644
--- a/shib-networking/pom.xml
+++ b/shib-networking/pom.xml
@@ -50,12 +50,6 @@
         <!-- Runtime Dependencies -->
 
         <!-- Test Dependencies -->
-        <dependency>
-            <groupId>org.openjdk.nashorn</groupId>
-            <artifactId>nashorn-core</artifactId>
-            <version>${nashorn.jdk.version}</version>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>${spring.groupId}</groupId>
             <artifactId>spring-core</artifactId>
@@ -71,9 +65,29 @@
             <artifactId>spring-test</artifactId>
             <scope>test</scope>
         </dependency>
-
     </dependencies>
 
+    <profiles>
+        <!--
+            Pull in a Javascript engine for testing in Java
+            versions where the JDK doesn't provide one.
+        -->
+        <profile>
+            <id>get-nashorn</id>
+            <activation>
+                <jdk>[15,</jdk>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.openjdk.nashorn</groupId>
+                    <artifactId>nashorn-core</artifactId>
+                    <version>${nashorn.jdk.version}</version>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+        </profile>
+    </profiles>
+
     <scm>
         <connection>${shibboleth.scm.connection}java-shib-shared</connection>
         <developerConnection>${shibboleth.scm.developerConnection}java-shib-shared</developerConnection>
diff --git a/shib-networking/src/main/java/net/shibboleth/utilities/java/support/ddf/DDF.java b/shib-networking/src/main/java/net/shibboleth/utilities/java/support/ddf/DDF.java
deleted file mode 100644
index 29273e7a..00000000
--- a/shib-networking/src/main/java/net/shibboleth/utilities/java/support/ddf/DDF.java
+++ /dev/null
@@ -1,1602 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.utilities.java.support.ddf;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URLDecoder;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.NotThreadSafe;
-
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
-import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-
-/**
- * The core object in the DDF mode, this is a node in a tree of objects that
- * make up the entire data structure.
- * 
- * <p>Each node contains references to its parant and children, if any,
- * as well as data type and possibly a value if a leaf node.</p>
- * 
- * <p>Most of the types are self-explanatory, but strings may be "safe" or "unsafe".
- * Safe strings are understood to be Unicode that can be safely converted between UTF-8
- * and UTF-16. Unsafe strings are represented as Java String objects but have an unknown
- * character encoding so the individual code points above 127 are essentially undefined
- * and cannot be assumed to represent the "correct" value. They may only be compared
- * with other values that are understood to represent the same range of values.</p> 
- * 
- * <p>The method names do not align to normal Java conventions for compatibility with
- * the other version(s) of the same API.</p>
- */
- at NotThreadSafe
-public class DDF implements Iterable<DDF> {
-
-    /** Name of node. */
-    @Nullable private String name;
-    
-    /** Parent node. */
-    @Nullable private DDF parent;
-
-    /** Type enum. */
-    public enum DDFType {
-
-        /** A null node. */
-        DDF_NULL(-1),
-
-        /** An empty node with no value. */
-        DDF_EMPTY(0),
-        
-        /** A string value. */
-        DDF_STRING(1),
-        
-        /** An integral value of no more than 32-bits. */
-        DDF_INT(2),
-        
-        /** A floating point value. */
-        DDF_FLOAT(3),
-        
-        /** A structure with named children. */
-        DDF_STRUCT(4),
-        
-        /** An ordered list. */
-        DDF_LIST(5),
-        
-        /** A reference to any object. */
-        DDF_POINTER(6),
-        
-        /** A string that cannot be assumed to be UTF-8 (see above docs). */
-        DDF_STRING_UNSAFE(7),
-        
-        /** An integral value of no more than 64-bits. */
-        DDF_LONG(8);
-        
-        /** Type value. */
-        private final int value;
-        
-        /**
-         * Constructor.
-         * 
-         * @param val value of the type enum
-         */
-        private DDFType(final int val) {
-            value = val;
-        }
-        
-        /**
-         * Get the type value.
-         * 
-         * @return type value
-         */
-        public int getValue() {
-            return value;
-        }
-        
-        /**
-         * Convert an integer into the corresponding enum value.
-         * 
-         * @param val input type
-         * 
-         * @return enum constant
-         * 
-         * @throws IllegalArgumentException if the type is out of range
-         */
-// Checkstyle: CyclomaticComplexity OFF
-        public static DDFType valueOf(final int val) throws IllegalArgumentException {
-            final DDFType type;
-            switch (val) {
-                case -1:
-                    type = DDF_NULL;
-                    break;
-                        
-                case 0:
-                    type = DDF_EMPTY;
-                    break;
-                        
-                case 1:
-                    type = DDF_STRING;
-                    break;
-                        
-                case 2:
-                    type = DDF_INT;
-                    break;
-
-                case 3:
-                    type = DDF_FLOAT;
-                    break;
-                    
-                case 4:
-                    type = DDF_STRUCT;
-                    break;
-                    
-                case 5:
-                    type = DDF_LIST;
-                    break;
-
-                case 6:
-                    type = DDF_POINTER;
-                    break;
-                    
-                case 7:
-                    type = DDF_STRING_UNSAFE;
-                    break;
-                
-                case 8:
-                    type = DDF_LONG;
-                    break;
-                    
-                default:
-                    throw new IllegalArgumentException("Unrecognized DDF type");
-            }
-            return type;
-        }
-        
-    };
-// Checkstyle: CyclomaticComplexity ON
-    
-    /** Node type. */
-    @Nonnull private DDFType type;
-    
-    /** Reference to the value, which depends on the type. */
-    @Nullable private Object value;
-    
-    /** Constructor. */
-    public DDF() {
-        type = DDFType.DDF_NULL;
-    }
-
-    /**
-     * Constructor.
-     *
-     * <p>For compatibility, the name is constrained to no more than 255 characters.</p>
-     *
-     * @param n node name
-     */
-    public DDF(@Nullable @NotEmpty final String n) {
-        type = DDFType.DDF_EMPTY;
-        name(n);
-    }
-
-    /**
-     * Constructor.
-     *
-     * <p>For compatibility, the name is constrained to no more than 255 characters.</p>
-     *
-     * @param n node name
-     * @param val string value, assumed to be "safe" Unicode
-     */
-    public DDF(@Nullable @NotEmpty final String n, @Nullable final String val) {
-        this(n);
-        string(val);
-    }
-
-    /**
-     * Constructor.
-     *
-     * <p>For compatibility, the name is constrained to no more than 255 characters.</p>
-     *
-     * @param n node name
-     * @param val byte array value, handled without knowledge of the encoding
-     */
-    public DDF(@Nullable @NotEmpty final String n, @Nullable final byte[] val) {
-        this(n);
-        unsafe_string(val);
-    }
-
-    /**
-     * Constructor.
-     *
-     * <p>For compatibility, the name is constrained to no more than 255 characters.</p>
-     *
-     * @param n node name
-     * @param val integer value
-     */
-    public DDF(@Nullable @NotEmpty final String n, final int val) {
-        this(n);
-        integer(val);
-    }
-
-    /**
-     * Constructor.
-     *
-     * <p>For compatibility, the name is constrained to no more than 255 characters.</p>
-     *
-     * @param n node name
-     * @param val long integer value
-     */
-    public DDF(@Nullable @NotEmpty final String n, final long val) {
-        this(n);
-        longinteger(val);
-    }
-
-    /**
-     * Constructor.
-     *
-     * <p>For compatibility, the name is constrained to no more than 255 characters.</p>
-     *
-     * @param n node name
-     * @param val floating value
-     */
-    public DDF(@Nullable @NotEmpty final String n, final double val) {
-        this(n);
-        floating(val);
-    }
-
-    /**
-     * Constructor.
-     *
-     * <p>For compatibility, the name is constrained to no more than 255 characters.</p>
-     *
-     * @param n node name
-     * @param val object value
-     */
-    public DDF(@Nullable @NotEmpty final String n, @Nullable final Object val) {
-        this(n);
-        pointer(val);
-    }
-
-    /**
-     * Destroys a node's content, resets it to a null object and clears its name.
-     * 
-     * <p>This is primarily for tree maintenance, given the lack of need for explicit
-     * memory management.</p>
-     * 
-     * @return this object
-     */
-    @Nonnull public DDF destroy() {
-        remove().empty().name(null);
-        type = DDFType.DDF_NULL;
-        return this;
-    }
-    
-    /**
-     * Performs a deep copy of the node and all children, if any.
-     * 
-     * @return the copy
-     */
-// Checkstyle: CyclomaticComplexity OFF
-    @SuppressWarnings("unchecked")
-    @Nonnull DDF copy() {
-        final DDF dup = new DDF(name);
-        
-        switch (type) {
-            case DDF_NULL:
-                dup.destroy();
-                break;
-                
-            case DDF_EMPTY:
-                break;
-                
-            case DDF_STRING:
-                dup.string((String) value);
-                break;
-                
-            case DDF_STRING_UNSAFE:
-                dup.unsafe_string((byte[]) value);
-                break;
-                
-            case DDF_INT:
-                dup.integer((Integer) value);
-                break;
-
-            case DDF_LONG:
-                dup.longinteger((Long) value);
-                break;
-                
-            case DDF_FLOAT:
-                dup.floating((Double) value);
-                break;
-                
-            case DDF_STRUCT:
-                dup.structure();
-                for (final DDF ddf : ((Map<String,DDF>) value).values()) {
-                    dup.add(ddf.copy());
-                }
-                break;
-                
-            case DDF_LIST:
-                dup.list();
-                for (final DDF ddf : (List<DDF>) value) {
-                    dup.add(ddf.copy());
-                }
-                break;
-                
-            default:
-        }
-        
-        return dup;
-    }
-// Checkstyle: CyclomaticComplexity ON
-    
-    /**
-     * Get the node name.
-     * 
-     * @return the name
-     */
-    @Nullable public String name() {
-        return name;
-    }
-    
-    /**
-     * Set the node name.
-     * 
-     * <p>For compatibility, the name is constrained to no more than 255 characters.</p>
-     * 
-     * <p>The name will not be set if the node is already a child of a structure.</p>
-     * 
-     * @param n the new name
-     * 
-     * @return this object
-     */
-    @Nonnull public DDF name(@Nullable @NotEmpty final String n) {
-        if (!isnull() && (parent == null || !parent.isstruct())) {
-            if (n != null) {
-                name = Constraint.isNotEmpty(n.substring(0,Integer.min(n.length(), 255)), "Name cannot be empty");
-            } else {
-                name = null;
-            }
-        }
-        return this;
-    }
-    
-    /**
-     * Returns true iff the node is null.
-     * 
-     * @return true iff the node is null
-     */
-    public boolean isnull() {
-        return type == DDFType.DDF_NULL;
-    }
-    
-    /**
-     * Returns true iff the node is empty.
-     * 
-     * @return true iff the node is empty
-     */
-    public boolean isempty() {
-        return type == DDFType.DDF_EMPTY;
-    }
-
-    /**
-     * Returns true iff the node is a string.
-     * 
-     * @return true iff the node is a string
-     */
-    public boolean isstring() {
-        return type == DDFType.DDF_STRING;
-    }
-
-    /**
-     * Returns true iff the node is an unsafe string.
-     * 
-     * @return true iff the node is an unsafe string
-     */
-    public boolean isunsafestring() {
-        return type == DDFType.DDF_STRING_UNSAFE;
-    }
-
-    /**
-     * Returns true iff the node is an integer.
-     * 
-     * @return true iff the node is an integer
-     */
-    public boolean isint() {
-        return type == DDFType.DDF_INT;
-    }
-
-    /**
-     * Returns true iff the node is a long integer.
-     * 
-     * @return true iff the node is a long integer
-     */
-    public boolean islong() {
-        return type == DDFType.DDF_LONG;
-    }
-    
-    /**
-     * Returns true iff the node is a floating point.
-     * 
-     * @return true iff the node is a floating point
-     */
-    public boolean isfloat() {
-        return type == DDFType.DDF_FLOAT;
-    }
-
-    /**
-     * Returns true iff the node is a structure.
-     * 
-     * @return true iff the node is a structure
-     */
-    public boolean isstruct() {
-        return type == DDFType.DDF_STRUCT;
-    }
-
-    /**
-     * Returns true iff the node is a list/array.
-     * 
-     * @return true iff the node is a list/array.
-     */
-    public boolean islist() {
-        return type == DDFType.DDF_LIST;
-    }
-
-    /**
-     * Returns true iff the node is a pointer (i.e., object reference).
-     * 
-     * @return true iff the node is a pointer (i.e., object reference)
-     */
-    public boolean ispointer() {
-        return type == DDFType.DDF_POINTER;
-    }
-
-    /**
-     * Get the string value of this node.
-     * 
-     * <p>The string value of a non-string value is null.</p>
-     * 
-     * @return the string value or null
-     */
-    @Nullable public String string() {
-        return isstring() ? (String) value : null;
-    }
-
-    /**
-     * Get the byte array value of this node if an unsafe string.
-     * 
-     * @return the byte array value or null
-     */
-// Checkstyle: MethodName OFF
-    @Nullable public byte[] unsafe_string() {
-        return isunsafestring() ? (byte[]) value : null;
-    }
-// Checkstyle: MethodName ON
-
-    /**
-     * Get the integer value of this node.
-     * 
-     * <p>Integers are coerced from other types based on numeric conversions
-     * or the count of a structure or list.</p> 
-     * 
-     * @return the integer value or null
-     */
-    @Nullable public Integer integer() {
-        
-        switch(type) {
-            case DDF_INT:
-                return (Integer) value;
-            case DDF_LONG:
-                return ((Long) value).intValue();
-            case DDF_FLOAT:
-                return ((Double) value).intValue();
-            case DDF_STRING:
-                try {
-                    return Integer.valueOf((String) value);
-                } catch (final NumberFormatException e) {
-                    // Swallow.
-                    return null;
-                }
-            case DDF_STRUCT:
-                return ((Map<?,?>) value).size();
-            case DDF_LIST:
-                return ((List<?>) value).size();
-            default:
-                break;
-        }
-        
-        return null;
-    }
-
-    /**
-     * Get the long integer value of this node.
-     * 
-     * <p>Longs are coerced from other types based on numeric conversions
-     * or the count of a structure or list.</p> 
-     * 
-     * @return the long integer value or null
-     */
-    @Nullable public Long longinteger() {
-        
-        switch(type) {
-            case DDF_INT:
-                return ((Integer) value).longValue();
-            case DDF_LONG:
-                return (Long) value;
-            case DDF_FLOAT:
-                return ((Double) value).longValue();
-            case DDF_STRING:
-                try {
-                    return Long.valueOf((String) value);
-                } catch (final NumberFormatException e) {
-                    // Swallow.
-                    return null;
-                }
-            case DDF_STRUCT:
-                return (long) ((Map<?,?>) value).size();
-            case DDF_LIST:
-                return (long) ((List<?>) value).size();
-            default:
-                break;
-        }
-        
-        return null;
-    }
-    
-    /**
-     * Get the floating point value of this node.
-     * 
-     * <p>Doubles are coerced from other types based on numeric conversions
-     * or the count of a structure or list.</p> 
-     *
-     * @return the floating point value or null
-     */
-    @Nullable public Double floating() {
-        
-        switch(type) {
-            case DDF_INT:
-                return ((Integer) value).doubleValue();
-            case DDF_LONG:
-                return ((Long) value).doubleValue();
-            case DDF_FLOAT:
-                return (Double) value;
-            case DDF_STRING:
-                try {
-                    return Double.valueOf((String) value);
-                } catch (final NumberFormatException e) {
-                    // Swallow.
-                    return null;
-                }
-            case DDF_STRUCT:
-                return (double) ((Map<?,?>) value).size();
-            case DDF_LIST:
-                return (double) ((List<?>) value).size();
-            default:
-                break;
-        }
-        
-        return null;
-    }
-
-    /**
-     * Get the pointer/reference value of this node, which is just an {@link Object}.
-     * 
-     * @return pointer/reference value or null
-     */
-    @Nullable public Object pointer() {
-        return ispointer() ? value : null;
-    }
-
-
-    /**
-     * Converts this node to an empty type/value.
-     * 
-     * <p>All children should be considered disposed of, though in Java this is
-     * circumventable by means of maintaining references to them.</p>
-     * 
-     * @return this object
-     */
-    @Nonnull public DDF empty() {
-        type = DDFType.DDF_EMPTY;
-        value = null;
-        return this;
-    }
-
-    /**
-     * Converts this node to a string type/value.
-     * 
-     * @param val the value to inject
-     * 
-     * @return this object
-     */
-    @Nonnull public DDF string(@Nullable final String val) {
-        empty();
-        value = val;
-        type = DDFType.DDF_STRING;
-        return this;
-    }
-
-    /**
-     * Converts this node to an unsafe string type/value.
-     * 
-     * @param val the value to inject
-     * 
-     * @return this object
-     */
-// Checkstyle: MethodName OFF
-    @Nonnull public DDF unsafe_string(@Nullable final byte[] val) {
-        empty();
-        value = val;
-        type = DDFType.DDF_STRING_UNSAFE;
-        return this;
-    }
-// Checkstyle: MethodName ON
-
-    /**
-     * Converts this node to a string type/value based on the converted form of the input.
-     * 
-     * @param val input value
-     * 
-     * @return this object
-     */
-    @Nonnull public DDF string(final int val) {
-        return string(Integer.toString(val));
-    }
-
-    /**
-     * Converts this node to a string type/value based on the converted form of the input.
-     * 
-     * @param val input value
-     * 
-     * @return this object
-     */
-    @Nonnull public DDF string(final long val) {
-        return string(Long.toString(val));
-    }
-    
-    /**
-     * Converts this node to a string type/value based on the converted form of the input.
-     * 
-     * @param val input value
-     * 
-     * @return this object
-     */
-    @Nonnull public DDF string(final double val) {
-        return string(Double.toString(val));
-    }
-
-    /**
-     * Converts this node to an integer type/value.
-     * 
-     * @param val value to inject
-     * 
-     * @return this object
-     */
-    @Nonnull public DDF integer(final int val) {
-        empty();
-        value = Integer.valueOf(val);
-        type = DDFType.DDF_INT;
-        return this;
-    }
-
-    /**
-     * Converts this node to an integer type/value based on the converted form of the input.
-     * 
-     * <p>A conversion error will assign zero as the value.</p>
-     * 
-     * @param val value to inject
-     * 
-     * @return this object
-     */
-    @Nonnull public DDF integer(@Nonnull @NotEmpty final String val) {
-        empty();
-        try {
-            return integer(Integer.valueOf(val));
-        } catch (final NumberFormatException e) {
-            return integer(0);
-        }
-    }
-
-    /**
-     * Converts this node to a long integer type/value.
-     * 
-     * @param val value to inject
-     * 
-     * @return this object
-     */
-    @Nonnull public DDF longinteger(final long val) {
-        empty();
-        value = Long.valueOf(val);
-        type = DDFType.DDF_LONG;
-        return this;
-    }
-
-    /**
-     * Converts this node to a long integer type/value based on the converted form of the input.
-     * 
-     * <p>A conversion error will assign zero as the value.</p>
-     * 
-     * @param val value to inject
-     * 
-     * @return this object
-     */
-    @Nonnull public DDF longinteger(@Nonnull @NotEmpty final String val) {
-        empty();
-        try {
-            return longinteger(Long.valueOf(val));
-        } catch (final NumberFormatException e) {
-            return longinteger(0);
-        }
-    }
-
-    /**
-     * Converts this node to an floating point type/value.
-     * 
-     * @param val value to inject
-     * 
-     * @return this object
-     */
-    @Nonnull public DDF floating(final double val) {
-        empty();
-        value = Double.valueOf(val);
-        type = DDFType.DDF_FLOAT;
-        return this;
-    }
-
-    /**
-     * Converts this node to a floating point type/value based on the converted form of the input.
-     * 
-     * <p>A conversion error will assign zero as the value.</p>
-     * 
-     * @param val value to inject
-     * 
-     * @return this object
-     */
-    @Nonnull public DDF floating(@Nonnull @NotEmpty final String val) {
-        empty();
-        try {
-            return floating(Double.valueOf(val));
-        } catch (final NumberFormatException e) {
-            return floating(0.0);
-        }
-    }
-
-    /**
-     * Converts this node to a structure.
-     * 
-     * @return this object
-     */
-    @Nonnull public DDF structure() {
-        empty();
-        value = new LinkedHashMap<String,DDF>();
-        type = DDFType.DDF_STRUCT;
-        return this;
-    }
-
-    /**
-     * Converts this node to a list/array.
-     * 
-     * @return this object
-     */
-    @Nonnull public DDF list() {
-        empty();
-        value = new ArrayList<DDF>();
-        type = DDFType.DDF_LIST;
-        return this;
-    }
-
-    /**
-     * Converts this node to a pointer/reference type.
-     * 
-     * @param val value to inject
-     * 
-     * @return this object
-     */
-    @Nonnull public DDF pointer(@Nonnull final Object val) {
-        empty();
-        value = val;
-        type = DDFType.DDF_POINTER;
-        return this;
-    }
-
-    /**
-     * Adds a node to the end of a struct or list and returns it.
-     * 
-     * <p>If this node is not a struct or list or the child is a null node, then it is returned
-     * with no further action.</p>
-     * 
-     * <p>If this node is a struct with an existing member by the same name, the input
-     * replaces that member.</p>
-     * 
-     * @param child the child to add
-     * 
-     * @return the child
-     */
-    @SuppressWarnings("unchecked")
-    @Nonnull public DDF add(@Nonnull final DDF child) {
-        if ((!isstruct() && !islist()) || child.isnull() || this == child.parent) {
-            return child;
-        }
-
-        if (isstruct()) {
-            if (child.name == null) {
-                return child;
-            }
-            getmember(child.name).destroy();
-            child.remove();
-            ((Map<String,DDF>) value).put(child.name, child);
-        } else {
-            child.remove();
-            ((List<DDF>) value).add(child);
-        }
-
-        child.parent = this;
-        return child;
-    }
-
-    /**
-     * Adds a node to a list prior to a specified node.
-     * 
-     * <p>If this node is not a list, does not contain the second parameter, or
-     * either parameter is a null node, then the first parameter is returned with
-     * no further action.</p> 
-     * 
-     * @param child the child to add
-     * @param before the node to insert the child before
-     * 
-     * @return the child
-     */
-    @Nonnull public DDF addbefore(@Nonnull final DDF child, @Nonnull final DDF before) {
-        if (!islist() || child.isnull() || before.parent != this) {
-            return child;
-        }
-
-        child.remove();
-        @SuppressWarnings("unchecked")
-        final List<DDF> list = (List<DDF>) value;
-        list.add(list.indexOf(before), child);
-        child.parent = this;
-        return child;
-    }
-
-    /**
-     * Adds a node to a list after a specified node.
-     * 
-     * <p>If this node is not a list, does not contain the second parameter, or
-     * either parameter is a null node, then the first parameter is returned with
-     * no further action.</p> 
-     * 
-     * @param child the child to add
-     * @param after the node to insert the child after
-     * 
-     * @return the child
-     */
-    @Nonnull public DDF addafter(@Nonnull final DDF child, @Nonnull final DDF after) {
-        if (!islist() || child.isnull() || after.parent != this) {
-            return child;
-        }
-
-        child.remove();
-        
-        @SuppressWarnings("unchecked")
-        final List<DDF> list = (List<DDF>) value;
-        
-        final int i = list.indexOf(after);
-        if (i == list.size() - 1) {
-            list.add(child);
-        } else {
-            list.add(i + 1, child);
-        }
-        child.parent = this;
-        
-        return child;
-    }
-    
-    /**
-     * Isolate this object from its surrounding nodes and return it.
-     * 
-     * @return this object
-     */
-    @SuppressWarnings("unchecked")
-    @Nonnull public DDF remove() {
-        if (parent != null) {
-            if (parent.isstruct()) {
-                ((Map<String,DDF>) parent.value).remove(name);
-            } else {
-                ((List<DDF>) parent.value).remove(this);
-            }
-            
-            parent = null;
-        }
-        return this;
-    }
-    
-    /**
-     * Get the parent node.
-     * 
-     * @return parent node
-     */
-    @Nullable public DDF parent() {
-        return parent;
-    }
-    
-    /**
-     * Expose an immutable map representing a structure node.
-     * 
-     * @return immutable map, or null if the node is not a structure
-     */
-    @SuppressWarnings("unchecked")
-    @Nonnull @NonnullElements @Unmodifiable @NotLive public Map<String,DDF> asMap() {
-        if (isstruct()) {
-            return Map.copyOf((Map<String,DDF>) value);
-        }
-        
-        return Collections.emptyMap();
-    }
-
-    /**
-     * Expose an immutable list representing a structure or list node.
-     * 
-     * @return immutable list, or null if the node is not a structure or list
-     */
-    @SuppressWarnings("unchecked")
-    @Nonnull @NonnullElements @Unmodifiable @NotLive public List<DDF> asList() {
-        if (isstruct()) {
-            return List.copyOf(((Map<String,DDF>) value).values());
-        } else if (islist()) {
-            return List.copyOf((List<DDF>) value);
-        }
-        
-        return Collections.emptyList();
-    }
-
-    /**
-     * Adds a new empty node to a structure, possibly creating nested structures based
-     * on dotted path notation (existing nodes matching the path segments are not altered
-     * other than to convert them to structures).
-     * 
-     * <p>The input path MUST contain at least one non-empty path segment.</p>
-     * 
-     * <p>This node will be converted to a structure if not already one.</p>
-     * 
-     * @param path dotted path to use
-     * 
-     * @return the last node added to the nested tree, or a null node if unable to do so
-     */
-    @Nonnull public DDF addmember(@Nonnull @NotEmpty final String path) {
-        final String[] tokens = Constraint.isNotEmpty(path, "Path cannot be null").split("\\.");
-        Constraint.isNotEmpty(tokens, "Path did not produce an array of path segments");
-        
-        if (!isnull()) {
-            DDF base = this;
-            for (final String segment : tokens) {
-                if (!base.isstruct()) {
-                    base.structure();
-                }
-                
-                DDF node = base.getmember(segment);
-                if (node.isnull()) {
-                    node = base.add(new DDF(segment));
-                }
-                
-                base = node;
-            }
-            
-            return base;
-        }
-        
-        return new DDF();
-    }
-
-    /**
-     * Access a (possibly nested) structure member via dotted path notation, also allowing access to
-     * list elements via "[n]" array notation.
-     * 
-     * <p>Failure to navigate the tree at any point will cause a null node to be returned.</p>
-     * 
-     * @param path dotted path to use
-     * 
-     * @return the matching node, or a null node
-     */
-// Checkstyle: CyclomaticComplexity OFF
-    @SuppressWarnings("unchecked")
-    @Nonnull public DDF getmember(@Nonnull @NotEmpty final String path) {
-        final String[] tokens = path.split("\\.");
-        if (tokens == null || tokens.length == 0 || isnull()) {
-            return new DDF();
-        }
-
-        DDF current = this;
-
-        for (int i = 0; i < tokens.length;) {
-            if (tokens[i].startsWith("[") && tokens[i].endsWith("]")) {
-                // Attempt to access a list entry via [n] notation and advance the path.
-                int index;
-                try {
-                    index = Integer.valueOf(tokens[i].substring(1, tokens[i].length() - 1));
-                } catch(final NumberFormatException e) {
-                    index = 0;
-                }
-                if (current.islist() && index < ((List<DDF>) current.value).size()) {
-                    current = ((List<DDF>) current.value).get(index);
-                } else {
-                    return new DDF();
-                }
-                i++;
-            } else if (current.isstruct()) {
-                // Access the named element and advance the path.
-                current = ((Map<String,DDF>) current.value).get(tokens[i]);
-                if (current == null) {
-                    return new DDF();
-                }
-                i++;
-            } else if (current.islist()) {
-                // Access first element of list, don't advance the path.
-                current = ((List<DDF>) current.value).get(0);
-                if (current == null) {
-                    return new DDF();
-                }
-            } else {
-                return new DDF();
-            }
-        }
-        
-        return current;
-    }
-
-    /** {@inheritDoc} */
-    @Nonnull public Iterator<DDF> iterator() {
-        final List<DDF> list = asList();
-        if (list != null) {
-            return list.iterator();
-        }
-        return Collections.emptyListIterator();
-    }
-    
-    /** {@inheritDoc} */
-    @Override
-    public boolean equals(final Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        
-        if (obj == null) {
-            return false;
-        }
-        
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        
-        final DDF other = (DDF) obj;
-        if (name == null) {
-            if (other.name != null) {
-                return false;
-            }
-        } else if (!name.equals(other.name)) {
-            return false;
-        }
-        
-        if (type != other.type) {
-            return false;
-        }
-        
-        if (value == null) {
-            if (other.value != null) {
-                return false;
-            }
-        } else if (!value.equals(other.value)) {
-            return false;
-        }
-        
-        return true;
-    }
-// Checkstyle: CyclomaticComplexity ON
-        
-    /** {@inheritDoc} */
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((name == null) ? 0 : name.hashCode());
-        result = prime * result + ((parent == null) ? 0 : parent.hashCode());
-        result = prime * result + ((type == null) ? 0 : type.hashCode());
-        result = prime * result + ((value == null) ? 0 : value.hashCode());
-        return result;
-    }
-
-    /** 
-     * {@inheritDoc}
-     * 
-     * <p>The string output is for debugging purposes and should not be used when serializing.</p>
-     */
-    @Override
-    @Nonnull public String toString() {
-        return dump(new StringBuilder(), 0).toString();
-    }
-
-// Checkstyle: MethodLength|CyclomaticComplexity OFF
-    /**
-     * Helper method to dump to a string for debugging.
-     * 
-     * @param builder string builder to use
-     * @param indent size of indent
-     * 
-     * @return the first parameter
-     */
-    @Nonnull private StringBuilder dump(@Nonnull final StringBuilder builder, final long indent) {
-        
-        for (long i = 0; i < indent; ++i) {
-            builder.append(' ');
-        }
-        
-        switch (type) {
-
-            case DDF_NULL:
-                builder.append("null");
-                break;
-                
-            case DDF_EMPTY:
-                builder.append("empty");
-                if (name != null) {
-                    builder.append(' ').append(name);
-                }
-                break;
-
-            case DDF_STRING:
-                builder.append("String");
-                if (name != null) {
-                    builder.append(' ').append(name);
-                }
-                builder.append(" = ");
-                if (value != null) {
-                    builder.append('"').append(((String) value).replace("\"", "\\\"")).append('"');
-                } else {
-                    builder.append("null");
-                }
-                break;
-                
-            case DDF_STRING_UNSAFE:
-                builder.append("byte[]");
-                if (name != null) {
-                    builder.append(' ').append(name);
-                }
-                builder.append(" = ");
-                if (value != null) {
-                    builder.append('{');
-                    for (final byte b : (byte[]) value) {
-                        builder.append(Integer.toHexString(b)).append(", ");
-                    }
-                    builder.append('}');
-                } else {
-                    builder.append("null");
-                }
-                break;
-
-            case DDF_INT:
-                builder.append("Integer");
-                if (name != null) {
-                    builder.append(' ').append(name);
-                }
-                builder.append(" = ").append(value);
-                break;
-
-            case DDF_LONG:
-                builder.append("Long");
-                if (name != null) {
-                    builder.append(' ').append(name);
-                }
-                builder.append(" = ").append(value);
-                break;
-
-            case DDF_FLOAT:
-                builder.append("Double");
-                if (name != null) {
-                    builder.append(' ').append(name);
-                }
-                builder.append(" = ").append(value);
-                break;
-
-            case DDF_STRUCT:
-                builder.append("struct");
-                if (name != null) {
-                    builder.append(' ').append(name);
-                }
-                builder.append(" = {");
-                if (!((Map<?,?>) value).isEmpty()) {
-                    builder.append('\n');
-                    for (final DDF child : this) {
-                        child.dump(builder, indent + 2);
-                    }
-                }
-                for (long i = 0; i < indent; ++i) {
-                    builder.append(' ');
-                }
-                builder.append('}');
-                break;
-
-            case DDF_LIST:
-                builder.append("DDF[").append(((List<?>) value).size()).append(']');
-                if (name != null) {
-                    builder.append(' ').append(name);
-                }
-                builder.append(" = {");
-
-                if (!((List<?>) value).isEmpty()) {
-                    builder.append('\n');
-                    for (final DDF child : this) {
-                        child.dump(builder, indent + 2);
-                    }
-                }
-                for (long i = 0; i < indent; ++i) {
-                    builder.append(' ');
-                }
-                builder.append('}');
-                break;
-
-            case DDF_POINTER:
-                builder.append("Object");
-                if (name != null) {
-                    builder.append(' ').append(name);
-                }
-                builder.append(" = ");
-                if (value != null) {
-                    builder.append(value);
-                } else {
-                    builder.append("null");
-                }
-                break;
-
-            default:
-                builder.append("UNKNOWN -- WARNING: ILLEGAL VALUE");
-        }
-        builder.append(";\n");
-        
-        return builder;
-    }
-    
-    /**
-     * Serialize this object to a provided stream.
-     * 
-     * @param os output stream
-     *
-     * @return the output stream
-     * 
-     * @throws IOException if an error occurs
-     */
-    @Nonnull public OutputStream serialize(@Nonnull final OutputStream os) throws IOException {
-        if (!isnull()) {
-            if (name != null) {
-                encode(os, name.getBytes("UTF8"));
-            } else {
-                os.write('.');
-            }
-            os.write(' ');
-
-            switch (type) {
-                case DDF_EMPTY:
-                case DDF_POINTER:
-                    os.write(Integer.toString(DDFType.DDF_EMPTY.getValue()).getBytes("UTF8"));
-                    os.write('\n');
-                    break;
-
-                case DDF_STRING:
-                    os.write(Integer.toString(type.getValue()).getBytes("UTF8"));
-                    if (value != null) {
-                        os.write(' ');
-                        encode(os, ((String) value).getBytes("UTF-8"));
-                    }
-                    os.write('\n');
-                    break;
-
-                case DDF_STRING_UNSAFE:
-                    os.write(Integer.toString(type.getValue()).getBytes("UTF8"));
-                    if (value != null) {
-                        os.write(' ');
-                        encode(os, (byte[]) value);
-                    }
-                    os.write('\n');
-                    break;
-
-                case DDF_INT:
-                    os.write(Integer.toString(type.getValue()).getBytes("UTF8"));
-                    os.write(' ');
-                    os.write(Integer.toString((Integer) value).getBytes("UTF8"));
-                    os.write('\n');
-                    break;
-
-                case DDF_LONG:
-                    os.write(Integer.toString(type.getValue()).getBytes("UTF8"));
-                    os.write(' ');
-                    os.write(Long.toString((Long) value).getBytes("UTF8"));
-                    os.write('\n');
-                    break;
-
-                case DDF_FLOAT:
-                    os.write(Integer.toString(type.getValue()).getBytes("UTF8"));
-                    os.write(' ');
-                    os.write(Double.toString((Double) value).getBytes("UTF8"));
-                    os.write('\n');
-                    break;
-
-                case DDF_STRUCT:
-                    @SuppressWarnings("unchecked")
-                    final Collection<DDF> members = ((Map<String,DDF>) value).values();
-                    os.write(Integer.toString(type.getValue()).getBytes("UTF8"));
-                    os.write(' ');
-                    os.write(Integer.toString(members.size()).getBytes("UTF8"));
-                    os.write('\n');
-                    for (final DDF child : members) {
-                        child.serialize(os);
-                    }
-                    break;
-
-                case DDF_LIST:
-                    @SuppressWarnings("unchecked")
-                    final Collection<DDF> children = (List<DDF>) value;
-                    os.write(Integer.toString(type.getValue()).getBytes("UTF8"));
-                    os.write(' ');
-                    os.write(Integer.toString(children.size()).getBytes("UTF8"));
-                    os.write('\n');
-                    for (final DDF child : children) {
-                        child.serialize(os);
-                    }
-                    break;
-
-                default:
-                    break;
-            }
-        }
-        
-        return os;
-    }
-    
-    /**
-     * Parses a seralized DDF from an input stream.
-     * 
-     * @param is input stream
-     * 
-     * @return the parsed object
-     * 
-     * @throws IOException if an error occurs
-     */
-// Checkstyle: ReturnCount OFF
-    @Nonnull public static DDF deserialize(@Nonnull final InputStream is) throws IOException {
-        
-        int ch;
-        final StringBuilder nameBuilder = new StringBuilder();
-
-        // First field is the name.
-        while ((ch = is.read()) != -1 && !Character.isWhitespace(ch)) {
-            if (ch >= 0 && ch <= 127) {
-                // The int is a code point from 0..255, but our grammar constrains this to 0..127 so
-                // this is a safe append, to promote the ASCII into Unicode.
-                nameBuilder.appendCodePoint(ch);
-            } else {
-                throw new IOException("Invalid code point outside US-ASCII range");
-            }
-        }
-        
-        if (ch != 0x20) {
-            // Name has to be followed by a space.
-            // This will also cover an early line or stream termination.
-            throw new IOException("Name not followed by space character");
-        }
-        
-        final String name = nameBuilder.toString();
-        if (name.isEmpty()) {
-            // No name field.
-            throw new IOException("Name field missing");
-        }
-        
-        final DDF obj = new DDF(null);
-        if (!".".equals(name)) {
-            // The name is stipulated to be UTF-8 safe so any high order ASCII characters are
-            // assumed to be part of a multi-byte sequence.
-            try {
-                obj.name(URLDecoder.decode(name, "UTF-8"));
-            } catch (final IllegalArgumentException e) {
-                throw new IOException(e);
-            }
-        }
-        
-        // Next field is the numeric type designation.
-        final StringBuilder typeBuilder = new StringBuilder();
-        while ((ch = is.read()) != -1 && Character.isDigit(ch)) {
-            // This is safe because the byte contract of the stream disallows
-            // any non-ASCII digit from satisfying the isDigit check.
-            typeBuilder.appendCodePoint(ch);
-        }
-        
-        // Before continuing, we convert the string into a DDF type.
-        final DDFType type;
-        try {
-            type = DDFType.valueOf(Integer.valueOf(typeBuilder.toString()));
-        } catch (final IllegalArgumentException e) {
-            throw new IOException("Invalid DDF type");
-        }
-
-        // Process typical value types.
-        final StringBuilder valueBuilder = new StringBuilder();
-        switch (type) {
-            case DDF_EMPTY:
-            case DDF_POINTER:
-                if (ch != 0x0A) {
-                    throw new IOException("Empty/pointer record not terminated by linefeed");
-                }
-                // Nothing else to do, it's already empty.
-                return obj;
-            
-            case DDF_STRING:
-            case DDF_STRING_UNSAFE:
-                if (ch == 0x0A) {
-                    if (type == DDFType.DDF_STRING) {
-                        return obj.string(null);
-                    }
-                    return obj.unsafe_string(null);
-                } else if (ch != 0x20) {
-                    throw new IOException("Type field not followed by space character");
-                }
-                
-                while ((ch = is.read()) != -1 && !Character.isWhitespace(ch)) {
-                    if (ch >= 0 && ch <= 127) {
-                        // The int is a code point from 0..255, but our grammar constrains this to 0..127 so
-                        // this is a safe append, to promote the ASCII into Unicode.
-                        valueBuilder.appendCodePoint(ch);
-                    } else {
-                        throw new IOException("Invalid code point outside US-ASCII range");
-                    }
-                }
-                
-                if (ch != 0x0A) {
-                    throw new IOException("String value not followed by linefeed");
-                }
-                
-                try {
-                    if (type == DDFType.DDF_STRING) {
-                        // String values are handled as UTF-8.
-                        return obj.string(URLDecoder.decode(valueBuilder.toString(), "UTF-8"));
-                    }
-                    
-                    // Unsafe string values are processed as ISO-8859-1.
-                    // They may be anything, but it will guarantee a single byte encoding.
-                    return obj.unsafe_string(
-                            URLDecoder.decode(valueBuilder.toString(), "ISO-8859-1").getBytes("ISO-8859-1"));
-                    
-                } catch (final IllegalArgumentException e) {
-                    throw new IOException(e);
-                }
-
-            case DDF_INT:
-            case DDF_LONG:
-            case DDF_FLOAT:
-                if (ch != 0x20) {
-                    throw new IOException("Type field not followed by space character");
-                }
-                
-                while ((ch = is.read()) != -1 && !Character.isWhitespace(ch)) {
-                    if (ch >= 0 && ch <= 127) {
-                        // The int is a code point from 0..255, but our grammar constrains this to 0..127 so
-                        // this is a safe append, to promote the ASCII into Unicode.
-                        valueBuilder.appendCodePoint(ch);
-                    } else {
-                        throw new IOException("Invalid code point outside US-ASCII range");
-                    }
-                }
-                
-                if (ch != 0x0A) {
-                    throw new IOException("Numeric value not followed by linefeed");
-                } else if (valueBuilder.length() == 0) {
-                    throw new IOException("Numeric value missing");
-                }
-                
-                if (type == DDFType.DDF_INT) {
-                    return obj.integer(valueBuilder.toString());
-                } else if (type == DDFType.DDF_LONG) {
-                    return obj.longinteger(valueBuilder.toString());
-                }
-                return obj.floating(valueBuilder.toString());
-                
-            case DDF_STRUCT:
-            case DDF_LIST:
-                if (ch != 0x20) {
-                    throw new IOException("Type field not followed by space character");
-                }
-
-                while ((ch = is.read()) != -1 && Character.isDigit(ch)) {
-                    // This is safe because the byte contract of the stream disallows
-                    // any non-ASCII digit from satisfying the isDigit check.
-                    valueBuilder.appendCodePoint(ch);
-                }
-                
-                if (ch != 0x0A) {
-                    throw new IOException("Record count not followed by linefeed");
-                } else if (valueBuilder.length() == 0) {
-                    throw new IOException("Record count missing");
-                }
-                
-                int count;
-                try {
-                    count = Integer.valueOf(valueBuilder.toString());
-                } catch (final NumberFormatException e) {
-                    throw new IOException("Invalid record count");
-                }
-                
-                if (type == DDFType.DDF_STRUCT) {
-                    obj.structure();
-                } else {
-                    obj.list();
-                }
-                
-                for (; count > 0; --count) {
-                    obj.add(deserialize(is));
-                }
-                return obj;
-
-            default:
-                throw new IOException("Unexpected record type");
-        }
-    }
-// Checkstyle: MethodLength|CyclomaticComplexity|ReturnCount ON
-
-    /**
-     * A simple encoder for non-ASCII characters.
-     * 
-     * <p>Made this package-accessible for unit testing.</p>
-     * 
-     * @param os output stream
-     * @param bytes bytes to encode
-     * 
-     * @throws IOException if an error occurs
-     */
-    static void encode(@Nonnull final OutputStream os, @Nonnull final byte[] bytes) throws IOException {
-        for (final byte b : bytes) {
-            final int i = Byte.toUnsignedInt(b);
-            if (i < 0x30 || i > 0x7A) {
-                os.write('%');
-                os.write(hexchar(i >>> 4));
-                os.write(hexchar(i & 0x0F));
-            } else {
-                os.write(b);
-            }
-        }
-    }
-    
-    /**
-     * Converts a byte into a hex character.
-     * 
-     * @param b input byte
-     * 
-     * @return the hex character equivalent (capitalized)
-     */
-    private static int hexchar(final int b) {
-        // 48 is '0' and 65 is 'A'
-        return (b <= 9) ? (48 + b) : (65 + b - 10);
-    }
-    
-}
\ No newline at end of file
diff --git a/shib-networking/src/main/java/net/shibboleth/utilities/java/support/ddf/DDFSupport.java b/shib-networking/src/main/java/net/shibboleth/utilities/java/support/ddf/DDFSupport.java
deleted file mode 100644
index 72ddffed..00000000
--- a/shib-networking/src/main/java/net/shibboleth/utilities/java/support/ddf/DDFSupport.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.utilities.java.support.ddf;
-
-import javax.annotation.Nonnull;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-import net.shibboleth.utilities.java.support.xml.ElementSupport;
-
-/**
- * Helper methods for {@link DDF} usage.
- * 
- * @since 9.0.0
- */
-public final class DDFSupport {
-
-    /** Name of child element member created by {@link #fromElement(Element)} method. */
-    @Nonnull @NotEmpty public static final String CHILD_ELEMENTS_MEMBER = "_children";
-
-    /** Name of content member created by {@link #fromElement(Element)} method. */
-    @Nonnull @NotEmpty public static final String CONTENT_MEMBER = "_content";
-
-    /** Private constructor. */
-    private DDFSupport() {
-        
-    }
-
-    /**
-     * Converts a DOM tree rooted at the input element into a {@link DDF} mirroring the tree.
-     *
-     * <p>The name of the object is the local name of the element. 
-     * 
-     * <p>Attributes are converted into named structure members based on the local names.</p>
-     * 
-     * <p>Child elements are recursively processed into a list named {@link #CHILD_ELEMENTS_MEMBER}.</p>
-     * 
-     * <p>Text content is stored in a structure member named {@link #CONTENT_MEMBER}.</p>
-     * 
-     * <p>Namespaces are ignored.</p>
-     * 
-     * @param element input element
-     * 
-     * @return the converted object
-     */
-    @Nonnull public static DDF fromElement(@Nonnull final Element element) {
-        
-        Constraint.isNotNull(element, "Element cannot be null");
-        
-        // Named after element.
-        final DDF obj = new DDF(element.getLocalName());
-        
-        // Each attribute is added as a string member.
-        final NamedNodeMap attrs = element.getAttributes();
-        if (attrs != null) {
-            for (int i = 0; i < attrs.getLength(); ++i) {
-                final Attr attr = (Attr) attrs.item(i);
-                obj.addmember(attr.getLocalName()).string(attr.getValue());
-            }
-        }
-
-        DDF children = null;
-        
-        // Recursively convert each child to a child DDF and add it to a list. 
-        Element child = ElementSupport.getFirstChildElement(element);
-        while (child != null) {
-            if (children == null) {
-                children = obj.addmember(CHILD_ELEMENTS_MEMBER).list();
-            }
-            children.add(fromElement(child));
-            child = ElementSupport.getNextSiblingElement(child);
-        }
-        
-        final String content = ElementSupport.getElementContentAsString(element);
-        if (content != null && !content.isBlank()) {
-            obj.addmember(CONTENT_MEMBER).string(content);
-        }
-        
-        return obj;
-    }
-    
-}
\ No newline at end of file
diff --git a/shib-networking/src/main/java/net/shibboleth/utilities/java/support/ddf/RemotedHttpServletRequest.java b/shib-networking/src/main/java/net/shibboleth/utilities/java/support/ddf/RemotedHttpServletRequest.java
deleted file mode 100644
index bf0a04e2..00000000
--- a/shib-networking/src/main/java/net/shibboleth/utilities/java/support/ddf/RemotedHttpServletRequest.java
+++ /dev/null
@@ -1,688 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.utilities.java.support.ddf;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.StringReader;
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.nio.charset.CharacterCodingException;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CodingErrorAction;
-import java.security.Principal;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.TimeZone;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.NotThreadSafe;
-import jakarta.servlet.AsyncContext;
-import jakarta.servlet.DispatcherType;
-import jakarta.servlet.ReadListener;
-import jakarta.servlet.RequestDispatcher;
-import jakarta.servlet.ServletContext;
-import jakarta.servlet.ServletException;
-import jakarta.servlet.ServletInputStream;
-import jakarta.servlet.ServletRequest;
-import jakarta.servlet.ServletResponse;
-import jakarta.servlet.http.Cookie;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import jakarta.servlet.http.HttpSession;
-import jakarta.servlet.http.HttpUpgradeHandler;
-import jakarta.servlet.http.Part;
-
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Multimap;
-
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
-import net.shibboleth.utilities.java.support.collection.Pair;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-import net.shibboleth.utilities.java.support.net.URISupport;
-
-/**
- * Wraps a {@link DDF} object reflecting a remoted message encapsulating an HTTP request.
- * 
- * <p>Potential TODOs are noted in various places. One outstanding issue is header case.
- * The SP code never did case-folding of the header names, so we may need to adjust that
- * on the C++ side to force-lower them in transit and then lower them on access.</p>
- * 
- */
- at NotThreadSafe
-public class RemotedHttpServletRequest implements HttpServletRequest {
-
-    /** Empty byte array for empty bodies. */
-    @Nonnull private static final byte[] EMPTY_BODY = new byte[0];
-    
-    /** UTF-8 decoder. */
-    @Nonnull private static final CharsetDecoder UTF_8 =
-            Charset.forName("UTF-8").newDecoder()
-                .onMalformedInput(CodingErrorAction.REPORT)
-                .onUnmappableCharacter(CodingErrorAction.REPORT);
-
-    /** ISO single byte decoder. */
-    @Nonnull private static final CharsetDecoder ISO_8859_1 =
-            Charset.forName("ISO-8859-1").newDecoder()
-                .onMalformedInput(CodingErrorAction.REPORT)
-                .onUnmappableCharacter(CodingErrorAction.REPORT);
-
-    /** Underlying object containing remoted data. */
-    @Nonnull private final DDF obj;
-    
-    /** Cookie array. */
-    @Nullable @NonnullElements private List<Cookie> cookies;
-    
-    /** Parameter map. */
-    @Nullable private Map<String, String[]> parameters;
-    
-    /**
-     * Constructor.
-     *
-     * @param ddf remoted request information
-     */
-    public RemotedHttpServletRequest(@Nonnull final DDF ddf) {
-        obj = Constraint.isNotNull(ddf, "DDF cannot be null");
-    }
-    
-    /**
-     * Gets the underlying object containing the remoted data.
-     * 
-     * @return remoted data object
-     */
-    @Nonnull public DDF getDDF() {
-        return obj;
-    }
-    
-    /** {@inheritDoc} */
-    public Object getAttribute(final String name) {
-        // TODO: might use this to expose certain "standard" pieces of information
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    public Enumeration<String> getAttributeNames() {
-        // TODO: adjust if we support the method above.
-        return Collections.emptyEnumeration();
-    }
-
-    /** {@inheritDoc} */
-    public String getCharacterEncoding() {
-        return "UTF-8";
-    }
-
-    /** {@inheritDoc} */
-    public void setCharacterEncoding(final String env) throws UnsupportedEncodingException {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public int getContentLength() {
-        final Integer i = obj.getmember("content_length").integer();
-        return i != null ? i : -1;
-    }
-
-    /** {@inheritDoc} */
-    public long getContentLengthLong() {
-        return getContentLength();
-    }
-
-    /** {@inheritDoc} */
-    public String getContentType() {
-        return obj.getmember("content_type").string();
-    }
-
-    /** {@inheritDoc} */
-    public ServletInputStream getInputStream() throws IOException {
-        final String body = obj.getmember("body").string();
-        if (body != null) {
-            // The body is always assumed to be safely encoded for our use cases.
-            return new BodyInputStream(body.getBytes("UTF-8"));
-        }
-        return new BodyInputStream(EMPTY_BODY);
-    }
-
-    /** {@inheritDoc} */
-    public String getParameter(final String name) {
-        final String[] values = getParameterMap().get(name);
-        if (values != null) {
-            return values[0];
-        }
-        
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    public Enumeration<String> getParameterNames() {
-        return Collections.enumeration(getParameterMap().keySet());
-    }
-
-    /** {@inheritDoc} */
-    public String[] getParameterValues(final String name) {
-        return getParameterMap().get(name);
-    }
-
-    /** {@inheritDoc} */
-    public Map<String, String[]> getParameterMap() {
-        if (parameters == null) {
-            parameters = new HashMap<>();
-            final Multimap<String,String> multimap = ArrayListMultimap.create();
-            final String qs = getQueryString();
-            if (qs != null) {
-                final List<Pair<String,String>> qparams = URISupport.parseQueryString(qs);
-                for (final Pair<String,String> p : qparams) {
-                    multimap.put(p.getFirst(), p.getSecond());
-                }
-            }
-            
-            if ("application/x-www-form-urlencoded".equals(getContentType())) {
-                final String body = obj.getmember("body").string();
-                if (body != null) {
-                    final List<Pair<String,String>> qparams = URISupport.parseQueryString(body);
-                    for (final Pair<String,String> p : qparams) {
-                        multimap.put(p.getFirst(), p.getSecond());
-                    }
-                }
-            }
-            
-            for (final Map.Entry<String,Collection<String>> entry : multimap.asMap().entrySet()) {
-                parameters.put(entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]));
-            }
-        }
-        
-        return parameters;
-    }
-
-    /** {@inheritDoc} */
-    public String getProtocol() {
-        final String protocol = obj.getmember("protocol").string();
-        return protocol != null ? protocol : "HTTP/1.1";
-    }
-
-    /** {@inheritDoc} */
-    public String getScheme() {
-        return obj.getmember("scheme").string();
-    }
-
-    /** {@inheritDoc} */
-    public String getServerName() {
-        return decodeUnsafeString(obj.getmember("hostname").unsafe_string());
-    }
-
-    /** {@inheritDoc} */
-    public int getServerPort() {
-        final Integer i = obj.getmember("port").integer();
-        return i != null ? i : -1;
-    }
-
-    /** {@inheritDoc} */
-    public BufferedReader getReader() throws IOException {
-        return new BufferedReader(new StringReader(obj.getmember("body").string()));
-    }
-
-    /** {@inheritDoc} */
-    public String getRemoteAddr() {
-        return obj.getmember("client_addr").string();
-    }
-
-    /** {@inheritDoc} */
-    public String getRemoteHost() {
-        return obj.getmember("client_addr").string();
-    }
-
-    /** {@inheritDoc} */
-    public void setAttribute(final String name, final Object o) {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public void removeAttribute(final String name) {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public Locale getLocale() {
-        throw new UnsupportedOperationException();        
-    }
-
-    /** {@inheritDoc} */
-    public Enumeration<Locale> getLocales() {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public boolean isSecure() {
-        return "https".equals(getScheme());
-    }
-
-    /** {@inheritDoc} */
-    public RequestDispatcher getRequestDispatcher(final String path) {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public String getRealPath(final String path) {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public int getRemotePort() {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public String getLocalName() {
-        // TODO: If we need this, should be configurable via the c'tor.
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public String getLocalAddr() {
-        // TODO: If we need this, should be configurable via the c'tor.
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public int getLocalPort() {
-        return getServerPort();
-    }
-
-    /** {@inheritDoc} */
-    public ServletContext getServletContext() {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public AsyncContext startAsync() throws IllegalStateException {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public AsyncContext startAsync(final ServletRequest servletRequest, final ServletResponse servletResponse)
-            throws IllegalStateException {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public boolean isAsyncStarted() {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    public boolean isAsyncSupported() {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    public AsyncContext getAsyncContext() {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public DispatcherType getDispatcherType() {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public String getAuthType() {
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    public Cookie[] getCookies() {
-        if (cookies == null) {
-            final String header = getHeader("Cookie");
-            if (header != null) {
-                final String[] carray = header.split(";");
-                if (carray != null) {
-                    cookies = new ArrayList<>(carray.length);
-                    for (final String c : carray) {
-                        final String[] nvpair = c.split("=", -1);
-                        if (nvpair.length == 2) {
-                            final String name = nvpair[0].trim();
-                            // This is a fallback cookie used for Safari to work around SameSite bugs.
-                            if (name.endsWith("_fgwars")) {
-                                name.substring(0, name.length() - 7);
-                            }
-                            cookies.add(new Cookie(name, nvpair[1]));
-                        }
-                    }
-                } else {
-                    cookies = Collections.emptyList();
-                }
-            } else {
-                cookies = Collections.emptyList();
-            }
-        }
-        
-        if (cookies.isEmpty()) {
-            return null;
-        }
-        return cookies.toArray(new Cookie[cookies.size()]);
-    }
-
-    /** {@inheritDoc} */
-    public long getDateHeader(final String name) {
-        final DDF h = obj.getmember("headers").getmember(name);
-        if (h.isstring()) {
-            try {
-                // TODO: there are a ton of valid formats but I don't think we really will need this anyway.
-                final SimpleDateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
-                formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
-                final Date d = formatter.parse(h.string());
-                if (d != null) {
-                    return d.getTime();
-                }
-            } catch (final Exception e) {
-                // Ignore for now.
-            }
-        }
-        return -1;
-    }
-
-    /** {@inheritDoc} */
-    public String getHeader(final String name) {
-        return decodeUnsafeString(obj.getmember("headers").getmember(name).unsafe_string());
-    }
-
-    /** {@inheritDoc} */
-    public Enumeration<String> getHeaders(final String name) {
-        final String s = decodeUnsafeString(obj.getmember("headers").getmember(name).unsafe_string());
-        if (s != null) {
-            return Collections.enumeration(Collections.singletonList(s));
-        }
-        return Collections.emptyEnumeration();
-    }
-
-    /** {@inheritDoc} */
-    public Enumeration<String> getHeaderNames() {
-        return Collections.enumeration(obj.getmember("headers").asMap().keySet());
-    }
-
-    /** {@inheritDoc} */
-    public int getIntHeader(final String name) {
-        final DDF h = obj.getmember("headers").getmember(name);
-        if (h.isstring()) {
-            return Integer.parseInt(decodeUnsafeString(h.unsafe_string()));
-        }
-        return -1;
-    }
-
-    /** {@inheritDoc} */
-    public String getMethod() {
-        return obj.getmember("method").string();
-    }
-
-    /** {@inheritDoc} */
-    public String getPathInfo() {
-        // TODO: If we need this, should be configurable via the c'tor.
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public String getPathTranslated() {
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    public String getContextPath() {
-        // TODO: If we need this, should be configurable via the c'tor.
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public String getQueryString() {
-        return obj.getmember("query").string();
-    }
-
-    /** {@inheritDoc} */
-    public String getRemoteUser() {
-        return obj.getmember("remote_user").string();
-    }
-
-    /** {@inheritDoc} */
-    public boolean isUserInRole(final String role) {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    public Principal getUserPrincipal() {
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    public String getRequestedSessionId() {
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    public String getRequestURI() {
-        return decodeUnsafeString(obj.getmember("uri").unsafe_string());
-    }
-
-    /** {@inheritDoc} */
-    public StringBuffer getRequestURL() {
-        final String url = decodeUnsafeString(obj.getmember("url").unsafe_string());
-        return new StringBuffer(url != null ? url : "");
-    }
-
-    /** {@inheritDoc} */
-    public String getServletPath() {
-        // TODO: If we need this, should be configurable via the c'tor.
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public HttpSession getSession(final boolean create) {
-        if (create) {
-            throw new UnsupportedOperationException();
-        }
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    public HttpSession getSession() {
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    public String changeSessionId() {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public boolean isRequestedSessionIdValid() {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    public boolean isRequestedSessionIdFromCookie() {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    public boolean isRequestedSessionIdFromURL() {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    public boolean isRequestedSessionIdFromUrl() {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    public boolean authenticate(final HttpServletResponse response) throws IOException, ServletException {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public void login(final String username, final String password) throws ServletException {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public void logout() throws ServletException {
-        
-    }
-
-    /** {@inheritDoc} */
-    public Collection<Part> getParts() throws IOException, ServletException {
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    public Part getPart(final String name) throws IOException, ServletException {
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    public <T extends HttpUpgradeHandler> T upgrade(final Class<T> handlerClass) throws IOException, ServletException {
-        throw new UnsupportedOperationException();
-    }
-    
-    /**
-     * Helper method to decode a byte buffer into either UTF-8 or ISO-8859-1.
-     * 
-     * @param buffer input buffer
-     * 
-     * @return encoded String form of the data
-     */
-    @Nullable private static String decodeUnsafeString(final byte[] buffer) {
-        
-        if (buffer == null) {
-            return null;
-        }
-        
-        final ByteBuffer wrapper = ByteBuffer.wrap(buffer);
-        
-        try {
-            return UTF_8.decode(wrapper).toString();
-        } catch (final CharacterCodingException e) {
-            
-        }
-        
-        try {
-            return ISO_8859_1.decode(wrapper).toString();
-        } catch (final CharacterCodingException e) {
-            
-        }
-        
-        return null;
-    }
-
-    /** Helper class cribbed from Spring. */
-    private static class BodyInputStream extends ServletInputStream {
-
-        /** Underlying stream. */
-        @Nonnull private final InputStream delegate;
-
-        /**
-         * Constructor.
-         *
-         * @param body body data
-         */
-        public BodyInputStream(final byte[] body) {
-            delegate = new ByteArrayInputStream(body);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public boolean isFinished() {
-            return false;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public boolean isReady() {
-            return true;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void setReadListener(final ReadListener readListener) {
-            throw new UnsupportedOperationException();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public int read() throws IOException {
-            return delegate.read();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public int read(final byte[] b, final int off, final int len) throws IOException {
-            return delegate.read(b, off, len);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public int read(final byte[] b) throws IOException {
-            return delegate.read(b);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public long skip(final long n) throws IOException {
-            return delegate.skip(n);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public int available() throws IOException {
-            return delegate.available();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void close() throws IOException {
-            delegate.close();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public synchronized void mark(final int readlimit) {
-            delegate.mark(readlimit);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public synchronized void reset() throws IOException {
-            delegate.reset();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public boolean markSupported() {
-            return delegate.markSupported();
-        }
-    }
-
-}
\ No newline at end of file
diff --git a/shib-networking/src/main/java/net/shibboleth/utilities/java/support/ddf/RemotedHttpServletResponse.java b/shib-networking/src/main/java/net/shibboleth/utilities/java/support/ddf/RemotedHttpServletResponse.java
deleted file mode 100644
index b9ff05b0..00000000
--- a/shib-networking/src/main/java/net/shibboleth/utilities/java/support/ddf/RemotedHttpServletResponse.java
+++ /dev/null
@@ -1,504 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.utilities.java.support.ddf;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.nio.charset.Charset;
-import java.text.SimpleDateFormat;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Locale;
-import java.util.Optional;
-import java.util.TimeZone;
-import java.util.stream.Collectors;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.NotThreadSafe;
-import jakarta.servlet.ServletOutputStream;
-import jakarta.servlet.WriteListener;
-import jakarta.servlet.http.Cookie;
-import jakarta.servlet.http.HttpServletResponse;
-
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-
-/**
- * Uses a {@link DDF} object to reflect an HTTP response back to a remote caller.
- */
- at NotThreadSafe
-public class RemotedHttpServletResponse implements HttpServletResponse {
-
-    /** Underlying object for remoted data. */
-    @Nonnull private final DDF obj;
-    
-    /** Size of each character buffer for output. */
-    private int bufferSize;
-    
-    /** Tracks committing of response. */
-    private boolean committed;
-    
-    /** A materialized output stream. */
-    @Nullable private BodyOutputStream outputStream;
-
-    /**
-     * Constructor.
-     *
-     * @param ddf object to capture response
-     */
-    public RemotedHttpServletResponse(@Nonnull final DDF ddf) {
-        obj = Constraint.isNotNull(ddf, "DDF cannot be null");
-        obj.structure();
-        bufferSize = 1024;
-    }
-    
-    /**
-     * Gets the underlying object containing the response data.
-     * 
-     * @return remoted data object
-     */
-    @Nonnull public DDF getDDF() {
-        return obj;
-    }
-    
-    /** {@inheritDoc} */
-    public String getCharacterEncoding() {
-        return "UTF-8";
-    }
-
-    /** {@inheritDoc} */
-    public String getContentType() {
-        return getHeader("Content-Type");
-    }
-
-    /** {@inheritDoc} */
-    public ServletOutputStream getOutputStream() throws IOException {
-        if (committed) {
-            throw new IllegalStateException("Response already committed");
-        }
-
-        if (outputStream == null) {
-            outputStream = new BodyOutputStream();
-        }
-        return outputStream;
-    }
-
-    /** {@inheritDoc} */
-    public PrintWriter getWriter() throws IOException {
-        return new PrintWriter(getOutputStream(), false, Charset.forName(getCharacterEncoding()));
-    }
-
-    /** {@inheritDoc} */
-    public void setCharacterEncoding(final String charset) {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public void setContentLength(final int len) {
-        setIntHeader("Content-Length", len);
-    }
-
-    /** {@inheritDoc} */
-    public void setContentLengthLong(final long len) {
-        setHeader("Content-Length", Long.toString(len));
-    }
-
-    /** {@inheritDoc} */
-    public void setContentType(final String type) {
-        setHeader("Content-Type", type);
-    }
-
-    /** {@inheritDoc} */
-    public void setBufferSize(final int size) {
-        bufferSize = size;
-    }
-
-    /** {@inheritDoc} */
-    public int getBufferSize() {
-        return bufferSize;
-    }
-
-    /** {@inheritDoc} */
-    public void flushBuffer() throws IOException {
-        // Just mark as committed to signal that status and headers are frozen.
-        committed = true;
-    }
-
-    /** {@inheritDoc} */
-    public void resetBuffer() {
-        if (committed) {
-            throw new IllegalStateException("Response already committed");
-        }
-        
-        if (outputStream != null) {
-            outputStream.reset();
-        }
-    }
-
-    /** {@inheritDoc} */
-    public boolean isCommitted() {
-        return committed;
-    }
-
-    /** {@inheritDoc} */
-    public void reset() {
-        if (committed) {
-            throw new IllegalStateException("Response already committed");
-        }
-        outputStream = null;
-        obj.structure();
-    }
-
-    /** {@inheritDoc} */
-    public void setLocale(final Locale loc) {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public Locale getLocale() {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public void addCookie(final Cookie cookie) {
-        // The C++ side already manages SameSite independently, so we'll likely continue that.
-        final StringBuffer buffer = new StringBuffer(cookie.getName()).append('=');
-        if (cookie.getValue() != null) {
-            buffer.append(cookie.getValue());
-        }
-        if (cookie.getMaxAge() >= 0) {
-            buffer.append("; MaxAge=").append(cookie.getMaxAge());
-        }
-        if (cookie.getPath() != null) {
-            buffer.append("; ").append("Path=").append(cookie.getPath());
-        }
-        if (cookie.getDomain() != null) {
-            buffer.append("; ").append("Domain=").append(cookie.getDomain());
-        }
-        if (cookie.getSecure()) {
-            buffer.append("; Secure");
-        }
-        if (cookie.isHttpOnly()) {
-            buffer.append("; HttpOnly");
-        }
-        addHeader("Set-Cookie", buffer.toString());
-    }
-
-    /** {@inheritDoc} */
-    public boolean containsHeader(final String name) {
-        for (final DDF header : obj.getmember("headers").asList()) {
-            if (name.equals(header.name())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    public String encodeURL(final String url) {
-        return url;
-    }
-
-    /** {@inheritDoc} */
-    public String encodeRedirectURL(final String url) {
-        return url;
-    }
-
-    /** {@inheritDoc} */
-    public String encodeUrl(final String url) {
-        return url;
-    }
-
-    /** {@inheritDoc} */
-    public String encodeRedirectUrl(final String url) {
-        return url;
-    }
-
-    /** {@inheritDoc} */
-    public void sendError(final int sc, final String msg) throws IOException {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public void sendError(final int sc) throws IOException {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@inheritDoc} */
-    public void sendRedirect(final String location) throws IOException {
-        if (committed) {
-            throw new IllegalStateException("Response already committed");
-        }
-
-        obj.getmember("response").remove();
-        obj.addmember("redirect").string(location);
-        committed = true;
-        outputStream = null;
-    }
-
-    /** {@inheritDoc} */
-    public void setDateHeader(final String name, final long date) {
-        unsetHeader(name);
-        addDateHeader(name, date);
-    }
-
-    /** {@inheritDoc} */
-    public void addDateHeader(final String name, final long date) {
-        final SimpleDateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
-        formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
-        addHeader(name, formatter.format(Date.from(Instant.ofEpochMilli(date))));
-    }
-
-    /** {@inheritDoc} */
-    public void setHeader(final String name, final String value) {
-        unsetHeader(name);
-        addHeader(name, value);
-    }
-
-    /** {@inheritDoc} */
-    public void addHeader(final String name, final String value) {
-        getHeaderList().add(new DDF(name).string(value));
-    }
-
-    /** {@inheritDoc} */
-    public void setIntHeader(final String name, final int value) {
-        unsetHeader(name);
-        addIntHeader(name, value);
-    }
-
-    /** {@inheritDoc} */
-    public void addIntHeader(final String name, final int value) {
-        getHeaderList().add(new DDF(name).integer(value));
-    }
-
-    /** {@inheritDoc} */
-    public void setStatus(final int sc) {
-        obj.addmember("response.status").integer(sc);
-    }
-
-    /** {@inheritDoc} */
-    public void setStatus(final int sc, final String sm) {
-        setStatus(sc);
-        obj.addmember("response.status_message").string(sm);
-    }
-
-    /** {@inheritDoc} */
-    public int getStatus() {
-        final Integer i = obj.getmember("response.status").integer();
-        return i != null ? i : -1;
-    }
-
-    /** {@inheritDoc} */
-    public String getHeader(final String name) {
-        final Optional<DDF> header =
-                obj.getmember("headers").asList()
-                    .stream()
-                    .filter(ddf -> name.equalsIgnoreCase(ddf.name()))
-                    .findFirst();
-        if (header.isPresent()) {
-            if (header.orElseThrow().isstring()) {
-                return header.orElseThrow().string();
-            }
-            return header.orElseThrow().integer().toString();
-        }
-        
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    public Collection<String> getHeaders(final String name) {
-        return obj.getmember("headers").asList()
-            .stream()
-            .filter(ddf -> name.equalsIgnoreCase(ddf.name()))
-            .map(DDF::string)
-            .collect(Collectors.toUnmodifiableList());
-    }
-
-    /** {@inheritDoc} */
-    public Collection<String> getHeaderNames() {
-        return obj.getmember("headers").asList()
-                .stream()
-                .map(DDF::name)
-                .collect(Collectors.toUnmodifiableSet());
-    }
-    
-    /**
-     * Removes any existing header(s) of this type.
-     * 
-     * @param name name of header to remove
-     */
-    private void unsetHeader(final @Nonnull @NotEmpty String name) {
-        
-        if (committed) {
-            throw new IllegalStateException("Response already committed");
-        }
-        
-        // This is safe because the asList copy is divorced from the original list
-        // but the DDF child objects are the same.
-        obj.getmember("headers").asList()
-            .stream()
-            .filter(ddf -> name.equalsIgnoreCase(ddf.name()))
-            .forEach(DDF::remove);
-    }
-    
-    /**
-     * Get the list node to which headers should be added.
-     * 
-     * @return a pre-existing list or a new one for mutation.
-     */
-    @Nonnull private DDF getHeaderList() {
-        
-        if (committed) {
-            throw new IllegalStateException("Response already committed");
-        }
-        
-        final DDF headers = obj.getmember("headers");
-        if (headers.islist()) {
-            return headers;
-        }
-        return obj.addmember("headers").list();
-    }
-
-    /** Wrapper allowing use of containers of arrays. */
-    private static final class ByteArrayWrapper {
-        
-        /** Current write position. */
-        private int offset;
-        
-        /** Wrapped array. */
-        private final byte[] buffer;
-        
-        /**
-         * Constructor.
-         *
-         * @param size buffer size
-         */
-        private ByteArrayWrapper(final int size) {
-            buffer = new byte[size];
-            offset = 0;
-        }
-        
-        /**
-         * Gets the buffer.
-         * 
-         * @return the buffer
-         */
-        @Nonnull private byte[] getBuffer() {
-            return buffer;
-        }
-        
-        /**
-         * Gets the offset.
-         * 
-         * @return the offset
-         */
-        private int getOffset() {
-            return offset;
-        }
-        
-        /**
-         * Writes a byte to the buffer.
-         * 
-         * @param b byte to write
-         * 
-         * @return true iff the buffer was large enough to accommodate the byte
-         */
-        private boolean write(final int b) {
-            if (offset < buffer.length) {
-                buffer[offset++] = Integer.valueOf(b).byteValue();
-                return true;
-            }
-            
-            return false;
-        }
-    }
-
-    /** A pseudo {@link ServletOutputStream} to catch output. */
-    private class BodyOutputStream extends ServletOutputStream {
-
-        
-        /** Internal buffers. */
-        @Nonnull @NonnullElements private final ArrayList<ByteArrayWrapper> bufferList;
-        
-        /** The currently filling buffer. */
-        @Nonnull private ByteArrayWrapper currentBuffer;
-        
-        /** Constructor. */
-        public BodyOutputStream() {
-            currentBuffer = new ByteArrayWrapper(bufferSize);
-            bufferList = new ArrayList<>(1);
-            bufferList.add(currentBuffer);
-        }
-        
-        /** {@inheritDoc} */
-        @Override
-        public boolean isReady() {
-            return true;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void setWriteListener(final WriteListener writeListener) {
-            throw new UnsupportedOperationException();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void write(final int b) throws IOException {
-            if (!currentBuffer.write(b)) {
-                currentBuffer = new ByteArrayWrapper(bufferSize);
-                bufferList.add(currentBuffer);
-                Constraint.isTrue(currentBuffer.write(b), "Fresh buffer cannot fail to accept data");
-            }
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void flush() throws IOException {
-            
-            int offset = 0;
-            final byte[] copy = new byte[((bufferList.size() - 1) * bufferSize) +
-                                         bufferList.get(bufferList.size() - 1).getOffset()];
-
-            for (final ByteArrayWrapper b : bufferList) {
-                System.arraycopy(b.getBuffer(), 0, copy, offset, b.getOffset());
-                offset += b.getOffset();
-            }
-            obj.addmember("response.data").unsafe_string(copy);
-            committed = true;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void close() throws IOException {
-            flush();
-        }
-
-        /** Clear all data written. */
-        private void reset() {
-            currentBuffer = new ByteArrayWrapper(bufferSize);
-            bufferList.clear();
-            bufferList.add(currentBuffer);
-        }
-    }
-
-}
\ No newline at end of file
diff --git a/shib-networking/src/test/java/net/shibboleth/utilities/java/support/ddf/DDFSupportTest.java b/shib-networking/src/test/java/net/shibboleth/utilities/java/support/ddf/DDFSupportTest.java
deleted file mode 100644
index 382b09be..00000000
--- a/shib-networking/src/test/java/net/shibboleth/utilities/java/support/ddf/DDFSupportTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.utilities.java.support.ddf;
-
-import java.io.IOException;
-import java.util.List;
-
-import javax.annotation.Nullable;
-
-import org.testng.Assert;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Ignore;
-import org.testng.annotations.Test;
-import org.w3c.dom.Document;
-
-import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
-import net.shibboleth.utilities.java.support.xml.BasicParserPool;
-import net.shibboleth.utilities.java.support.xml.XMLParserException;
-
-/**
- * Unit test for {@link DDFSupport}.
- */
- at Ignore
-public class DDFSupportTest {
-    
-    @Nullable private BasicParserPool parserPool;
-    
-    /**
-     * Init parser.
-     * 
-     * @throws ComponentInitializationException 
-     */
-    @BeforeClass
-    public void setUp() throws ComponentInitializationException {
-        parserPool = new BasicParserPool();
-        parserPool.initialize();
-    }
-    
-   /**
-    * Teardown. 
-    */
-    @AfterClass
-   public void tearDown() {
-       parserPool.destroy();
-   }
-    
-    /**
-     * Test conversion.
-     * 
-     * @throws IOException 
-     * @throws XMLParserException 
-     */
-    @Test
-    public void test() throws XMLParserException, IOException {
-        final Document doc = parserPool.parse(getClass().getResourceAsStream("zork.xml"));
-        final DDF ddf = DDFSupport.fromElement(doc.getDocumentElement());
-        
-        Assert.assertNotNull(ddf);
-        Assert.assertEquals(ddf.name(), "root");
-        Assert.assertEquals(ddf.getmember("foo").string(), "bar");
-
-        final List<DDF> children = ddf.getmember(DDFSupport.CHILD_ELEMENTS_MEMBER).asList();
-        Assert.assertEquals(children.size(), 2);
-        
-        DDF child = children.get(0);
-        Assert.assertEquals(child.name(), "zork");
-        Assert.assertEquals(child.getmember("zorkmids").integer(), 10);
-        Assert.assertEquals(child.getmember("underground").string(), "true");
-        Assert.assertTrue(child.getmember(DDFSupport.CONTENT_MEMBER).isnull());
-        Assert.assertTrue(child.getmember(DDFSupport.CHILD_ELEMENTS_MEMBER).isnull());
-
-        child = children.get(1);
-        Assert.assertEquals(child.name(), "frobnitz");
-        Assert.assertEquals(child.getmember(DDFSupport.CONTENT_MEMBER).string(), "grue");
-        Assert.assertTrue(child.getmember(DDFSupport.CHILD_ELEMENTS_MEMBER).isnull());
-
-        Assert.assertTrue(ddf.getmember(DDFSupport.CONTENT_MEMBER).isnull());
-    }
-
-}
\ No newline at end of file
diff --git a/shib-networking/src/test/java/net/shibboleth/utilities/java/support/ddf/DDFTest.java b/shib-networking/src/test/java/net/shibboleth/utilities/java/support/ddf/DDFTest.java
deleted file mode 100644
index 086697f2..00000000
--- a/shib-networking/src/test/java/net/shibboleth/utilities/java/support/ddf/DDFTest.java
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.utilities.java.support.ddf;
-
-import static org.testng.Assert.*;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-
-import javax.annotation.Nonnull;
-
-import org.testng.annotations.Ignore;
-import org.testng.annotations.Test;
-
-import net.shibboleth.utilities.java.support.collection.Pair;
-
-/**
- * DDF unit tests.
- */
- at Ignore
-public class DDFTest {
-
-    @Test
-    public void testConstructors() {
-        DDF obj = new DDF();
-        assertNull(obj.name());
-        assertTrue(obj.isnull());
-        
-        obj = new DDF("foo");
-        assertEquals(obj.name(), "foo");
-        assertTrue(obj.isempty());
-        
-        obj = new DDF("foo", "bar");
-        assertEquals(obj.name(), "foo");
-        assertTrue(obj.isstring());
-        assertEquals(obj.string(), "bar");
-
-        obj = new DDF("foo", 42);
-        assertEquals(obj.name(), "foo");
-        assertTrue(obj.isint());
-        assertEquals(obj.integer(), Integer.valueOf(42));
-
-        obj = new DDF("foo", 42000000000L);
-        assertEquals(obj.name(), "foo");
-        assertTrue(obj.islong());
-        assertEquals(obj.longinteger(), Long.valueOf(42000000000L));
-
-        obj = new DDF("foo", 42.42);
-        assertEquals(obj.name(), "foo");
-        assertTrue(obj.isfloat());
-        assertEquals(obj.floating(), Double.valueOf(42.42));
-    }
-
-    @Test
-    public void testConversions() throws UnsupportedEncodingException {
-        final DDF obj = new DDF("foo");
-        obj.string("bar");
-        assertTrue(obj.isstring());
-        assertEquals(obj.string(), "bar");
-        assertNull(obj.integer());
-        assertNull(obj.floating());
-        
-        obj.string(42);
-        assertTrue(obj.isstring());
-        assertEquals(obj.string(), "42");
-        assertEquals(obj.integer(), Integer.valueOf(42));
-        assertEquals(obj.floating(), Double.valueOf(42));
-
-        obj.string(42.42);
-        assertTrue(obj.isstring());
-        assertEquals(obj.string(), "42.42");
-        assertNull(obj.integer());
-        assertEquals(obj.floating(), Double.valueOf(42.42));
-        
-        obj.integer(42);
-        assertTrue(obj.isint());
-        assertEquals(obj.integer(), Integer.valueOf(42));
-        assertEquals(obj.floating(), Double.valueOf(42));
-        
-        obj.integer("42");
-        assertTrue(obj.isint());
-        assertEquals(obj.integer(), Integer.valueOf(42));
-        assertEquals(obj.floating(), Double.valueOf(42));
-                
-        obj.longinteger(42000000000L);
-        assertTrue(obj.islong());
-        assertEquals(obj.longinteger(), Long.valueOf(42000000000L));
-        assertEquals(obj.floating(), Double.valueOf(42000000000L));
-
-        obj.longinteger("42000000000");
-        assertTrue(obj.islong());
-        assertEquals(obj.longinteger(), Long.valueOf(42000000000L));
-        assertEquals(obj.floating(), Double.valueOf(42000000000L));
-
-        obj.floating(42.42);
-        assertTrue(obj.isfloat());
-        assertEquals(obj.integer(), Integer.valueOf(42));
-        assertEquals(obj.floating(), Double.valueOf(42.42));
-        
-        obj.unsafe_string("bar".getBytes("ISO-8859-1"));
-        System.out.print(obj);
-    }
-    
-    @Test
-    public void testLists() {
-        final DDF obj = new DDF().list();
-        assertTrue(obj.islist());
-        assertEquals(obj.integer(), Integer.valueOf(0));
-        
-        obj.add(new DDF("foo", "bar"));
-        obj.add(new DDF("foo2", 42));
-        obj.add(new DDF("foo3").pointer(new Pair<>()));
-        assertEquals(obj.integer(), Integer.valueOf(3));
-        
-        for (final DDF el : obj) {
-            switch (el.name()) {
-                case "foo":
-                    assertEquals(el.string(), "bar");
-                    break;
-                
-                case "foo2":
-                    assertEquals(el.integer(), Integer.valueOf(42));
-                    break;
-                        
-                case "foo3":
-                    assertEquals(el.pointer(), new Pair<>());
-                    break;
-                        
-                default:
-                    fail("Node unrecognized");
-            }
-        }
-        
-        assertEquals(obj.getmember("[0]"), new DDF("foo", "bar"));
-        assertEquals(obj.getmember("[1]"), new DDF("foo2", 42));
-        assertTrue(obj.getmember("[3]").isnull());
-        
-        obj.addafter(new DDF(null), obj.getmember("[0]"));
-        assertEquals(obj.integer(), Integer.valueOf(4));
-        assertTrue(obj.getmember("[1]").isempty());
-
-        obj.addbefore(new DDF("foo4"), obj.getmember("[2]"));
-        assertEquals(obj.integer(), Integer.valueOf(5));
-        assertTrue(obj.getmember("[2]").name().equals("foo4"));
-        
-        assertTrue(obj.asList().get(4).remove().ispointer());
-        assertEquals(obj.integer(), Integer.valueOf(4));
-    }
-
-    @Test
-    public void testStructures() {
-        final DDF obj = new DDF().structure();
-        assertTrue(obj.isstruct());
-        assertEquals(obj.integer(), Integer.valueOf(0));
-        
-        obj.add(new DDF("foo", "bar"));
-        assertEquals(obj.integer(), Integer.valueOf(1));
-        assertTrue(obj.getmember("foo").name().equals("foo"));
-        assertTrue(obj.getmember("foo").string().equals("bar"));
-        
-        obj.addmember("foo2").integer(42);
-        assertEquals(obj.integer(), Integer.valueOf(2));
-        
-        obj.addmember("foo2.foo3").string("bar3");
-        assertEquals(obj.integer(), Integer.valueOf(2));
-        assertTrue(obj.getmember("foo2").isstruct());
-        assertEquals(obj.getmember("foo2").integer(), Integer.valueOf(1));
-        assertTrue(obj.getmember("foo2").getmember("foo3").string().equals("bar3"));
-        assertTrue(obj.getmember("foo2.foo3").string().equals("bar3"));
-    }
-    
-    @Test
-    public void testEncoder() throws IOException {
-        try (final ByteArrayOutputStream sink = new ByteArrayOutputStream()) {
-            DDF.encode(sink, "foo".getBytes("UTF8"));
-            assertEquals(sink.toString(), "foo");
-            sink.reset();
-            
-            DDF.encode(sink, "foo bar".getBytes("UTF8"));
-            assertEquals(sink.toString(), "foo%20bar");
-            sink.reset();
-            
-            DDF.encode(sink, "foo\nbar".getBytes("UTF8"));
-            assertEquals(sink.toString(), "foo%0Abar");
-            sink.reset();
-            
-            DDF.encode(sink, "foo☯️bar".getBytes("UTF8"));
-            assertEquals(sink.toString(), "foo%E2%98%AF%EF%B8%8Fbar");
-            sink.reset();
-            
-            // -128 corresponds to 128, which is the extended ASCII Euro symbol.
-            // This test demonstrates that round-tripping through such an encoding
-            // will preserve the original 0x80 hex value in that position in the string
-            // rather than converting through the UTF-8 representation.
-            final byte[] unsafe = {102, 111, 111, -128, 98, 97, 114};
-            DDF.encode(sink, new String(unsafe, "ISO-8859-1").getBytes("ISO-8859-1"));
-            assertEquals(sink.toString(), "foo%80bar");
-            sink.reset();
-        }
-    }
-    
-    @Test
-    public void testSerialize() throws IOException {
-        
-        try (final ByteArrayOutputStream sink = new ByteArrayOutputStream()) {
-            DDF obj = new DDF(null);
-            obj.serialize(sink);
-            assertEquals(sink.toByteArray(), testFile("empty-noname.ddf"));
-            sink.reset();
-            
-            obj.name("foo bar");
-            obj.serialize(sink);
-            assertEquals(sink.toByteArray(), testFile("empty-name.ddf"));
-            sink.reset();
-            
-            obj.string("zorkmid☯️");
-            obj.serialize(sink);
-            assertEquals(sink.toByteArray(), testFile("string-name.ddf"));
-            sink.reset();
-
-            final byte[] unsafe = {102, 111, 111, -128, 98, 97, 114};
-            obj.unsafe_string(unsafe);
-            obj.serialize(sink);
-            assertEquals(sink.toByteArray(), testFile("unsafestring-name.ddf"));
-            sink.reset();
-            
-            obj.integer(42);
-            obj.serialize(sink);
-            assertEquals(sink.toByteArray(), testFile("int-name.ddf"));
-            sink.reset();
-
-            obj.longinteger(42000000000L);
-            obj.serialize(sink);
-            assertEquals(sink.toByteArray(), testFile("long-name.ddf"));
-            sink.reset();
-
-            obj.floating(42.1315927);
-            obj.serialize(sink);
-            assertEquals(sink.toByteArray(), testFile("float-name.ddf"));
-            sink.reset();
-            
-            obj.structure();
-            obj.serialize(sink);
-            assertEquals(sink.toByteArray(), testFile("struct-empty.ddf"));
-            sink.reset();
-            
-            obj.addmember("infocom.zork").list().add(new DDF().integer(1));
-            obj.getmember("infocom.zork").add(new DDF().integer(2));
-            obj.getmember("infocom.zork").add(new DDF().integer(3));
-            obj.serialize(sink);
-            assertEquals(sink.toByteArray(), testFile("struct-complex.ddf"));
-            sink.reset();
-        }
-    }
-    
-    /**
-     * Convert test file contents to a byte array.
-     * 
-     * @param name file name
-     * 
-     * @return byte array
-     * 
-     * @throws IOException on error
-     */
-    private byte[] testFile(@Nonnull final String name) throws IOException {
-        return getClass().getResourceAsStream(name).readAllBytes();
-    }
-    
-    @Test
-    public void testDeserialize() throws IOException {
-        try (final InputStream is = getClass().getResourceAsStream("empty-noname.ddf")) {
-            final DDF obj = DDF.deserialize(is);
-            assertTrue(obj.isempty());
-            assertNull(obj.name());
-        }
-        
-        try (final InputStream is = getClass().getResourceAsStream("empty-name.ddf")) {
-            final DDF obj = DDF.deserialize(is);
-            assertTrue(obj.isempty());
-            assertEquals(obj.name(), "foo bar");
-        }
-        
-        try (final InputStream is = getClass().getResourceAsStream("string-name.ddf")) {
-            final DDF obj = DDF.deserialize(is);
-            assertTrue(obj.isstring());
-            assertEquals(obj.name(), "foo bar");
-            assertEquals(obj.string(), "zorkmid☯️");
-        }
-
-        try (final InputStream is = getClass().getResourceAsStream("unsafestring-name.ddf")) {
-            final DDF obj = DDF.deserialize(is);
-            assertTrue(obj.isunsafestring());
-            assertEquals(obj.name(), "foo bar");
-            final byte[] unsafe = {102, 111, 111, -128, 98, 97, 114};
-            assertEquals(obj.unsafe_string(), unsafe);
-        }
-
-        try (final InputStream is = getClass().getResourceAsStream("int-name.ddf")) {
-            final DDF obj = DDF.deserialize(is);
-            assertTrue(obj.isint());
-            assertEquals(obj.name(), "foo bar");
-            assertEquals(obj.integer(), Integer.valueOf(42));
-        }
-        
-        try (final InputStream is = getClass().getResourceAsStream("long-name.ddf")) {
-            final DDF obj = DDF.deserialize(is);
-            assertTrue(obj.islong());
-            assertEquals(obj.name(), "foo bar");
-            assertEquals(obj.longinteger(), Long.valueOf(42000000000L));
-        }
-
-        try (final InputStream is = getClass().getResourceAsStream("float-name.ddf")) {
-            final DDF obj = DDF.deserialize(is);
-            assertTrue(obj.isfloat());
-            assertEquals(obj.name(), "foo bar");
-            assertEquals(obj.floating(), Double.valueOf(42.1315927));
-        }
-
-        try (final InputStream is = getClass().getResourceAsStream("struct-empty.ddf")) {
-            final DDF obj = DDF.deserialize(is);
-            assertTrue(obj.isstruct());
-            assertEquals(obj.name(), "foo bar");
-            assertEquals(obj.integer(), Integer.valueOf(0));
-        }
-
-        try (final InputStream is = getClass().getResourceAsStream("struct-complex.ddf")) {
-            final DDF obj = DDF.deserialize(is);
-            assertTrue(obj.isstruct());
-            assertEquals(obj.name(), "foo bar");
-            assertEquals(obj.integer(), Integer.valueOf(1));
-            assertTrue(obj.getmember("infocom").isstruct());
-            assertTrue(obj.getmember("infocom.zork").islist());
-            assertEquals(obj.getmember("infocom.zork").integer(), Integer.valueOf(3));
-            assertEquals(obj.getmember("infocom.zork.[0]").integer(), Integer.valueOf(1));
-            assertEquals(obj.getmember("infocom.zork.[1]").integer(), Integer.valueOf(2));
-            assertEquals(obj.getmember("infocom.zork.[2]").integer(), Integer.valueOf(3));
-        }
-    }
-    
-    @Test
-    public void testBadInputs() {
-        try (final InputStream is = new ByteArrayInputStream(new String().getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-
-        try (final InputStream is = new ByteArrayInputStream(new String("\n").getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-
-        try (final InputStream is = new ByteArrayInputStream(new String(" ").getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-
-        try (final InputStream is = new ByteArrayInputStream(new String(".\n").getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-
-        try (final InputStream is = new ByteArrayInputStream(new String(". \n").getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-
-        try (final InputStream is = new ByteArrayInputStream(new String(". -2").getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-
-        try (final InputStream is = new ByteArrayInputStream(new String(". 0 \n").getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-
-        try (final InputStream is = new ByteArrayInputStream(new String(". 1 foo \n").getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-
-        try (final InputStream is = new ByteArrayInputStream(new String(". 2\n").getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-
-        try (final InputStream is = new ByteArrayInputStream(new String(". 2 \n").getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-
-        try (final InputStream is = new ByteArrayInputStream(new String(". 3\n").getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-
-        try (final InputStream is = new ByteArrayInputStream(new String(". 3 \n").getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-
-        try (final InputStream is = new ByteArrayInputStream(new String(". 4 \n").getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-
-        try (final InputStream is = new ByteArrayInputStream(new String(". 4\n").getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-
-        try (final InputStream is = new ByteArrayInputStream(new String(". 4 2\n. 1 foo\n").getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-        
-        try (final InputStream is = new ByteArrayInputStream(new String(". 5 foo\n").getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-
-        try (final InputStream is = new ByteArrayInputStream(new String(". 5 1\n").getBytes("UTF-8"))) {
-            DDF.deserialize(is);
-            fail("Should have thrown IOException");
-        } catch (final IOException e) {
-            
-        }
-    }
-    
-}
\ No newline at end of file
diff --git a/shib-networking/src/test/java/net/shibboleth/utilities/java/support/ddf/RemotedHttpServletRequestTest.java b/shib-networking/src/test/java/net/shibboleth/utilities/java/support/ddf/RemotedHttpServletRequestTest.java
deleted file mode 100644
index 255d8d24..00000000
--- a/shib-networking/src/test/java/net/shibboleth/utilities/java/support/ddf/RemotedHttpServletRequestTest.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.utilities.java.support.ddf;
-
-import static org.testng.Assert.*;
-
-import java.io.IOException;
-import java.util.List;
-
-import jakarta.servlet.http.Cookie;
-
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Ignore;
-import org.testng.annotations.Test;
-import org.testng.reporters.Files;
-
-/**
- * Unit test for {@link RemotedHttpServletRequest}.
- */
- at Ignore
-public class RemotedHttpServletRequestTest {
-    
-    private DDF obj;
-    private RemotedHttpServletRequest req;
-    
-    @BeforeMethod
-    public void setUp() {
-        obj = new DDF();
-        req = new RemotedHttpServletRequest(obj);
-    }
-    
-    @Test
-    public void testEmpty() throws IOException {
-        assertEquals(req.getContentLength(), -1);
-        assertEquals(req.getContentType(), null);
-        assertEquals(req.getCookies(), null);
-        assertEquals(req.getHeader("foo"), null);
-        assertEquals(req.getInputStream().read(), -1);
-        assertEquals(req.getMethod(), null);
-        assertEquals(req.getParameter("foo"), null);
-        assertEquals(req.getQueryString(), null);
-        assertEquals(req.getRemoteAddr(), null);
-        assertEquals(req.getRemoteUser(), null);
-        assertEquals(req.getRequestURI(), null);
-        assertEquals(req.getRequestURL().toString(), "");
-        assertEquals(req.getScheme(), null);
-        assertFalse(req.isSecure());
-        assertEquals(req.getServerPort(), -1);
-    }
-
-    @Test
-    public void testBasics() throws IOException {
-        obj.structure();
-        obj.addmember("content_length").integer(100);
-        obj.addmember("content_type").string("text/xml");
-        obj.addmember("method").string("POST");
-        obj.addmember("body").string("<foo/>");
-        obj.addmember("port").integer(80);
-        obj.addmember("client_addr").string("127.0.0.1");
-        obj.addmember("remote_user").string("jdoe");
-        obj.addmember("hostname").unsafe_string("localhost".getBytes("UTF-8"));
-        obj.addmember("uri").unsafe_string("/endpoint".getBytes("UTF-8"));
-        obj.addmember("url").unsafe_string("http://localhost/endpoint".getBytes("UTF-8"));
-        obj.addmember("scheme").string("http");
-        
-        assertEquals(req.getContentLength(), 100);
-        assertEquals(req.getContentType(), "text/xml");
-        assertEquals(req.getCookies(), null);
-        assertEquals(req.getHeader("foo"), null);
-        assertEquals(Files.streamToString(req.getInputStream()), "<foo/>");
-        assertEquals(req.getMethod(), "POST");
-        assertEquals(req.getParameter("foo"), null);
-        assertEquals(req.getQueryString(), null);
-        assertEquals(req.getRemoteAddr(), "127.0.0.1");
-        assertEquals(req.getRemoteUser(), "jdoe");
-        assertEquals(req.getServerName(), "localhost");
-        assertEquals(req.getRequestURI(), "/endpoint");
-        assertEquals(req.getRequestURL().toString(), "http://localhost/endpoint");
-        assertEquals(req.getScheme(), "http");
-        assertFalse(req.isSecure());
-        assertEquals(req.getServerPort(), 80);        
-    }
-    
-    @Test
-    public void testOneQueryParameter() throws IOException {
-        obj.structure();
-        obj.addmember("content_type").string("text/xml");
-        obj.addmember("body").string("<foo/>");
-        obj.addmember("query").string("foo=bar+baz");
-        
-        assertEquals(req.getParameterNames().nextElement(), "foo");
-        assertEquals(req.getParameter("foo"), "bar baz");
-    }
-
-    @Test
-    public void testMultiQueryParameters() throws IOException {
-        obj.structure();
-        obj.addmember("content_type").string("text/xml");
-        obj.addmember("body").string("<foo/>");
-        obj.addmember("query").string("foo=bar+baz&zork=grue&foo=baf");
-        
-        assertEquals(req.getParameter("foo"), "bar baz");
-        assertEquals(req.getParameterValues("foo"), List.of("bar baz", "baf").toArray());
-        assertEquals(req.getParameter("zork"), "grue");
-    }
-
-    @Test
-    public void testFormParameters() throws IOException {
-        obj.structure();
-        obj.addmember("content_type").string("application/x-www-form-urlencoded");
-        obj.addmember("body").string("foo=baf");
-        obj.addmember("query").string("foo=bar+baz&zork=grue");
-        
-        assertEquals(req.getParameter("foo"), "bar baz");
-        assertEquals(req.getParameterValues("foo"), List.of("bar baz", "baf").toArray());
-        assertEquals(req.getParameter("zork"), "grue");
-    }
-
-    @Test
-    public void testHeaders() throws IOException {
-        obj.structure();
-        obj.addmember("headers.foo").unsafe_string("bar".getBytes("UTF-8"));
-        obj.addmember("headers.zork").unsafe_string("grue".getBytes("UTF-8"));
-        
-        assertEquals(req.getHeaders("foo").nextElement(), "bar");
-        assertEquals(req.getHeader("zork"), "grue");
-        assertNull(req.getHeader("baz"));
-    }
-
-    @Test
-    public void testCookie() throws IOException {
-        obj.structure();
-        obj.addmember("headers.Cookie").unsafe_string("foo=bar;".getBytes("UTF-8"));
-        
-        final Cookie[] cookies = req.getCookies();
-        
-        assertEquals(cookies.length, 1);
-        assertEquals(cookies[0].getName(), "foo");
-        assertEquals(cookies[0].getValue(), "bar");
-    }
-
-    @Test
-    public void testCookies() throws IOException {
-        obj.structure();
-        obj.addmember("headers.Cookie").unsafe_string("foo=bar; zork=grue".getBytes("UTF-8"));
-        
-        final Cookie[] cookies = req.getCookies();
-        
-        assertEquals(cookies.length, 2);
-        assertEquals(cookies[0].getName(), "foo");
-        assertEquals(cookies[0].getValue(), "bar");
-        assertEquals(cookies[1].getName(), "zork");
-        assertEquals(cookies[1].getValue(), "grue");
-    }
-
-}
\ No newline at end of file
diff --git a/shib-networking/src/test/java/net/shibboleth/utilities/java/support/ddf/RemotedHttpServletResponseTest.java b/shib-networking/src/test/java/net/shibboleth/utilities/java/support/ddf/RemotedHttpServletResponseTest.java
deleted file mode 100644
index 5853dac9..00000000
--- a/shib-networking/src/test/java/net/shibboleth/utilities/java/support/ddf/RemotedHttpServletResponseTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.utilities.java.support.ddf;
-
-import static org.testng.Assert.*;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.time.Instant;
-import java.util.Set;
-
-import jakarta.servlet.http.Cookie;
-
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Ignore;
-import org.testng.annotations.Test;
-
-/**
- * Unit test for {@link RemotedHttpServletResponse}.
- */
- at Ignore
-public class RemotedHttpServletResponseTest {
-    
-    private DDF obj;
-    private RemotedHttpServletResponse resp;
-    
-    @BeforeMethod
-    public void setUp() {
-        obj = new DDF();
-        resp = new RemotedHttpServletResponse(obj);
-    }
-    
-    @Test
-    public void testBasics() throws IOException {
-        
-        resp.setContentType("text/xml");
-        resp.setHeader("Cache-Control", "private");
-        resp.addHeader("foo", "foo");
-        resp.setHeader("Foo", "bar");
-        resp.addDateHeader("Foo", Instant.now().toEpochMilli());
-        resp.addIntHeader("Bar", 42);
-        resp.setContentLength(42);
-        
-        final Cookie cookie = new Cookie("cookie1", "value1");
-        cookie.setSecure(true);
-        cookie.setHttpOnly(true);
-        cookie.setPath("/idp");
-        resp.addCookie(cookie);
-        
-        assertEquals(resp.getContentType(), "text/xml");
-        assertEquals((Set<String>) resp.getHeaderNames(), Set.of("Content-Type", "Cache-Control", "Foo", "Bar", "Content-Length", "Set-Cookie"));
-        assertTrue(resp.getHeaders("foo").contains("bar"));
-        assertEquals(resp.getHeader("Bar"), "42");
-        
-        final DDF headers = obj.getmember("headers");
-        assertTrue(headers.islist());
-        final DDF cheader = headers.asList().stream().filter(ddf -> "Set-Cookie".equalsIgnoreCase(ddf.name())).findFirst().orElseThrow();
-        assertEquals(cheader.string(), "cookie1=value1; Path=/idp; Secure; HttpOnly");
-    }
-
-    @Test
-    public void testRedirect() throws IOException {
-        resp.sendRedirect("http://localhost");
-
-        assertTrue(resp.isCommitted());
-        assertEquals(obj.getmember("redirect").string(), "http://localhost");
-        
-        try {
-            resp.getOutputStream();
-            fail("Response should have been committed.");
-        } catch (final IllegalStateException e) {
-            
-        }
-    }
-    
-    @Test
-    public void testResponseStream() throws IOException {
-        resp.setBufferSize(3);
-        resp.setStatus(200);
-        try (final OutputStream os = resp.getOutputStream()) {
-            os.write("zorkmid".getBytes("UTF-8"));
-        }
-        
-        assertTrue(resp.isCommitted());
-        assertEquals(obj.getmember("response.status").integer(), Integer.valueOf(200));
-        assertEquals(obj.getmember("response.data").unsafe_string(), "zorkmid".getBytes("UTF-8"));
-    }
-    
-    @Test
-    public void testResponseStream2() throws IOException {
-        resp.setBufferSize(3);
-        resp.setStatus(200);
-        try (final OutputStream os = resp.getOutputStream()) {
-            os.write("zorkmid☯️".getBytes("ISO-8859-1"));
-        }
-        
-        assertTrue(resp.isCommitted());
-        assertEquals(obj.getmember("response.status").integer(), Integer.valueOf(200));
-        assertEquals(obj.getmember("response.data").unsafe_string(), "zorkmid☯️".getBytes("ISO-8859-1"));
-    }
-    
-    @Test
-    public void testWriter() throws IOException {
-        resp.setBufferSize(3);
-        resp.setStatus(200);
-        try (final PrintWriter pw = resp.getWriter()) {
-            pw.print("zorkmid");
-        }
-        
-        assertTrue(resp.isCommitted());
-        assertEquals(obj.getmember("response.status").integer(), Integer.valueOf(200));
-        assertEquals(obj.getmember("response.data").unsafe_string(), "zorkmid".getBytes("UTF-8"));
-    }
-
-    @Test
-    public void testWriter2() throws IOException {
-        resp.setBufferSize(3);
-        resp.setStatus(200);
-        try (final PrintWriter pw = resp.getWriter()) {
-            pw.print("zorkmid☯️");
-        }
-        
-        assertTrue(resp.isCommitted());
-        assertEquals(obj.getmember("response.status").integer(), Integer.valueOf(200));
-        assertEquals(obj.getmember("response.data").unsafe_string(), "zorkmid☯️".getBytes("UTF-8"));
-    }
-}
\ No newline at end of file
diff --git a/shib-security/pom.xml b/shib-security/pom.xml
index 9336308f..ecc78234 100644
--- a/shib-security/pom.xml
+++ b/shib-security/pom.xml
@@ -38,12 +38,10 @@
             <artifactId>jcommander</artifactId>
         </dependency>
         <dependency>
-            <!--  Required if you're using classes from the security package. -->
             <groupId>org.bouncycastle</groupId>
             <artifactId>bcprov-jdk15on</artifactId>
         </dependency>
         <dependency>
-            <!--  Required if you're using classes from the security package. -->
             <groupId>org.bouncycastle</groupId>
             <artifactId>bcpkix-jdk15on</artifactId>
         </dependency>
@@ -58,19 +56,6 @@
         <!-- Runtime Dependencies -->
 
         <!-- Test Dependencies -->
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>shib-testing</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        
-        <dependency>
-            <groupId>org.openjdk.nashorn</groupId>
-            <artifactId>nashorn-core</artifactId>
-            <version>${nashorn.jdk.version}</version>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>${spring.groupId}</groupId>
             <artifactId>spring-core</artifactId>
@@ -86,9 +71,29 @@
             <artifactId>spring-test</artifactId>
             <scope>test</scope>
         </dependency>
-
     </dependencies>
 
+    <profiles>
+        <!--
+            Pull in a Javascript engine for testing in Java
+            versions where the JDK doesn't provide one.
+        -->
+        <profile>
+            <id>get-nashorn</id>
+            <activation>
+                <jdk>[15,</jdk>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.openjdk.nashorn</groupId>
+                    <artifactId>nashorn-core</artifactId>
+                    <version>${nashorn.jdk.version}</version>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+        </profile>
+    </profiles>
+
     <scm>
         <connection>${shibboleth.scm.connection}java-shib-shared</connection>
         <developerConnection>${shibboleth.scm.developerConnection}java-shib-shared</developerConnection>
diff --git a/shib-security/src/main/java/net/shibboleth/utilities/java/support/security/impl/BasicAccessControlService.java b/shib-security/src/main/java/net/shibboleth/utilities/java/support/security/impl/BasicAccessControlService.java
index a3b09cb1..eedd836c 100644
--- a/shib-security/src/main/java/net/shibboleth/utilities/java/support/security/impl/BasicAccessControlService.java
+++ b/shib-security/src/main/java/net/shibboleth/utilities/java/support/security/impl/BasicAccessControlService.java
@@ -30,7 +30,6 @@ import org.slf4j.LoggerFactory;
 import jakarta.servlet.ServletRequest;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.component.AbstractIdentifiableInitializableComponent;
-import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 import net.shibboleth.utilities.java.support.security.AccessControl;
 import net.shibboleth.utilities.java.support.security.AccessControlService;
diff --git a/shib-security/src/test/java/net/shibboleth/utilities/java/support/security/impl/BasicKeystoreKeyStrategyTest.java b/shib-security/src/test/java/net/shibboleth/utilities/java/support/security/impl/BasicKeystoreKeyStrategyTest.java
index 7ce88600..7fee684f 100644
--- a/shib-security/src/test/java/net/shibboleth/utilities/java/support/security/impl/BasicKeystoreKeyStrategyTest.java
+++ b/shib-security/src/test/java/net/shibboleth/utilities/java/support/security/impl/BasicKeystoreKeyStrategyTest.java
@@ -23,7 +23,6 @@ import java.time.Duration;
 
 import net.shibboleth.utilities.java.support.security.BasicKeystoreKeyStrategyTool;
 import net.shibboleth.utilities.java.support.security.TestResourceConverter;
-import net.shibboleth.utilities.java.support.security.impl.BasicKeystoreKeyStrategy;
 
 import org.springframework.core.io.FileSystemResource;
 import org.testng.Assert;
diff --git a/shib-service/.check-m2 b/shib-service/.check-m2
new file mode 100644
index 00000000..048849a0
--- /dev/null
+++ b/shib-service/.check-m2
@@ -0,0 +1 @@
+This file provokes a signature check of the maven repository unless overridden by the no-check-m2 property.
\ No newline at end of file
diff --git a/shib-service/.checkstyle b/shib-service/.checkstyle
new file mode 100644
index 00000000..186d7f35
--- /dev/null
+++ b/shib-service/.checkstyle
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<fileset-config file-format-version="1.2.0" simple-config="false" sync-formatter="false">
+
+    <local-check-config name="Shibboleth Checkstyle" location="/java-shib-shared/resources/checkstyle/checkstyle.xml" type="project" description="">
+        <additional-data name="cache-file" value="true"/>
+        <additional-data name="cache-props-file-location" value="null_1312636288299_cache.properties"/>
+        <additional-data name="cache-file-location" value="null_1312636288299_cache.xml"/>
+    </local-check-config>
+  
+    <fileset name="main source" enabled="true" check-config-name="Shibboleth Checkstyle" local="true">
+        <file-match-pattern match-pattern="src/main/java/.*\.java$" include-pattern="true"/>
+    </fileset>
+  
+</fileset-config>
diff --git a/shib-service/.gitignore b/shib-service/.gitignore
new file mode 100644
index 00000000..d8e6f876
--- /dev/null
+++ b/shib-service/.gitignore
@@ -0,0 +1,21 @@
+# A simulation of Subversion default ignores, generated by reposurgeon.
+*.o
+*.lo
+*.la
+*.al
+*.libs
+*.so
+*.so.[0-9]*
+*.a
+*.pyc
+*.pyo
+*.rej
+*.iml
+*~
+*.#*
+.*.swp
+.DS_store
+# Simulated Subversion default ignores end here
+# The contents of the svn:ignore property on the branch root.
+/test-output
+/target
diff --git a/shib-networking/pom.xml b/shib-service/pom.xml
similarity index 68%
copy from shib-networking/pom.xml
copy to shib-service/pom.xml
index c23fcc90..6f09322c 100644
--- a/shib-networking/pom.xml
+++ b/shib-service/pom.xml
@@ -10,12 +10,12 @@
         <version>9.0.0-SNAPSHOT</version>
     </parent>
 
-    <name>Shibboleth Shared :: Networking Support</name>
-    <artifactId>shib-networking</artifactId>
+    <name>Shibboleth Shared :: Services Support</name>
+    <artifactId>shib-service</artifactId>
     <packaging>jar</packaging>
 
     <properties>
-        <automatic.module.name>net.shibboleth.shared.networking</automatic.module.name>
+        <automatic.module.name>net.shibboleth.shared.service</automatic.module.name>
         <checkstyle.configLocation>${project.basedir}/../resources/checkstyle/checkstyle.xml</checkstyle.configLocation>
     </properties>
 
@@ -28,44 +28,52 @@
         </dependency>
 
         <dependency>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpclient</artifactId>
+            <groupId>net.shibboleth.ext</groupId>
+            <artifactId>spring-extensions</artifactId>
+            <version>${project.version}</version>
         </dependency>
+
         <dependency>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpclient-cache</artifactId>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>shib-security</artifactId>
+            <version>${project.version}</version>
         </dependency>
+        
         <dependency>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpcore</artifactId>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <scope>compile</scope> <!-- Normally runtime. -->
         </dependency>
-
-        <!-- Provided Dependencies -->
         <dependency>
-            <groupId>jakarta.servlet</groupId>
-            <artifactId>jakarta.servlet-api</artifactId>
-            <scope>provided</scope>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-core</artifactId>
+            <scope>compile</scope> <!-- Normally runtime. -->
+        </dependency>
+        
+        <dependency>
+            <groupId>io.dropwizard.metrics</groupId>
+            <artifactId>metrics-core</artifactId>
         </dependency>
 
-        <!-- Runtime Dependencies -->
-
-        <!-- Test Dependencies -->
         <dependency>
-            <groupId>org.openjdk.nashorn</groupId>
-            <artifactId>nashorn-core</artifactId>
-            <version>${nashorn.jdk.version}</version>
-            <scope>test</scope>
+            <groupId>${spring.groupId}</groupId>
+            <artifactId>spring-context</artifactId>
         </dependency>
         <dependency>
             <groupId>${spring.groupId}</groupId>
             <artifactId>spring-core</artifactId>
-            <scope>test</scope>
         </dependency>
+
+        <!-- Provided Dependencies -->
         <dependency>
-            <groupId>${spring.groupId}</groupId>
-            <artifactId>spring-web</artifactId>
-            <scope>test</scope>
+            <groupId>jakarta.servlet</groupId>
+            <artifactId>jakarta.servlet-api</artifactId>
+            <scope>provided</scope>
         </dependency>
+
+        <!-- Runtime Dependencies -->
+
+        <!-- Test Dependencies -->
         <dependency>
             <groupId>${spring.groupId}</groupId>
             <artifactId>spring-test</artifactId>
diff --git a/shib-spring/src/main/java/net/shibboleth/ext/spring/service/AbstractServiceableComponent.java b/shib-service/src/main/java/net/shibboleth/ext/spring/service/AbstractServiceableComponent.java
similarity index 100%
rename from shib-spring/src/main/java/net/shibboleth/ext/spring/service/AbstractServiceableComponent.java
rename to shib-service/src/main/java/net/shibboleth/ext/spring/service/AbstractServiceableComponent.java
diff --git a/shib-spring/src/main/java/net/shibboleth/ext/spring/service/ApplicationContextServiceStrategy.java b/shib-service/src/main/java/net/shibboleth/ext/spring/service/ApplicationContextServiceStrategy.java
similarity index 100%
rename from shib-spring/src/main/java/net/shibboleth/ext/spring/service/ApplicationContextServiceStrategy.java
rename to shib-service/src/main/java/net/shibboleth/ext/spring/service/ApplicationContextServiceStrategy.java
diff --git a/shib-spring/src/main/java/net/shibboleth/ext/spring/service/ApplicationContextServiceableComponent.java b/shib-service/src/main/java/net/shibboleth/ext/spring/service/ApplicationContextServiceableComponent.java
similarity index 100%
rename from shib-spring/src/main/java/net/shibboleth/ext/spring/service/ApplicationContextServiceableComponent.java
rename to shib-service/src/main/java/net/shibboleth/ext/spring/service/ApplicationContextServiceableComponent.java
diff --git a/shib-spring/src/main/java/net/shibboleth/ext/spring/service/ClassBasedServiceStrategy.java b/shib-service/src/main/java/net/shibboleth/ext/spring/service/ClassBasedServiceStrategy.java
similarity index 100%
rename from shib-spring/src/main/java/net/shibboleth/ext/spring/service/ClassBasedServiceStrategy.java
rename to shib-service/src/main/java/net/shibboleth/ext/spring/service/ClassBasedServiceStrategy.java
diff --git a/shib-spring/src/main/java/net/shibboleth/ext/spring/service/ReloadableSpringService.java b/shib-service/src/main/java/net/shibboleth/ext/spring/service/ReloadableSpringService.java
similarity index 100%
rename from shib-spring/src/main/java/net/shibboleth/ext/spring/service/ReloadableSpringService.java
rename to shib-service/src/main/java/net/shibboleth/ext/spring/service/ReloadableSpringService.java
diff --git a/shib-spring/src/main/java/net/shibboleth/ext/spring/service/package-info.java b/shib-service/src/main/java/net/shibboleth/ext/spring/service/package-info.java
similarity index 100%
rename from shib-spring/src/main/java/net/shibboleth/ext/spring/service/package-info.java
rename to shib-service/src/main/java/net/shibboleth/ext/spring/service/package-info.java
diff --git a/shib-support/src/main/java/net/shibboleth/utilities/java/support/service/LoggingService.java b/shib-service/src/main/java/net/shibboleth/shared/service/LoggingService.java
similarity index 92%
rename from shib-support/src/main/java/net/shibboleth/utilities/java/support/service/LoggingService.java
rename to shib-service/src/main/java/net/shibboleth/shared/service/LoggingService.java
index 1b161cdb..18584198 100644
--- a/shib-support/src/main/java/net/shibboleth/utilities/java/support/service/LoggingService.java
+++ b/shib-service/src/main/java/net/shibboleth/shared/service/LoggingService.java
@@ -15,11 +15,12 @@
  * limitations under the License.
  */
 
-package net.shibboleth.utilities.java.support.service;
+package net.shibboleth.shared.service;
 
 import javax.annotation.Nonnull;
 
 import net.shibboleth.utilities.java.support.resource.Resource;
+import net.shibboleth.utilities.java.support.service.ReloadableService;
 
 /**
  * A logging configuration abstraction that piggybacks on the {@link ReloadableService} interface.
diff --git a/shib-spring/src/main/java/net/shibboleth/ext/spring/service/LogbackLoggingService.java b/shib-service/src/main/java/net/shibboleth/shared/service/impl/LogbackLoggingService.java
similarity index 98%
rename from shib-spring/src/main/java/net/shibboleth/ext/spring/service/LogbackLoggingService.java
rename to shib-service/src/main/java/net/shibboleth/shared/service/impl/LogbackLoggingService.java
index d8ebb0ba..3f977371 100644
--- a/shib-spring/src/main/java/net/shibboleth/ext/spring/service/LogbackLoggingService.java
+++ b/shib-service/src/main/java/net/shibboleth/shared/service/impl/LogbackLoggingService.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.ext.spring.service;
+package net.shibboleth.shared.service.impl;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -36,6 +36,7 @@ import ch.qos.logback.core.joran.spi.JoranException;
 import ch.qos.logback.core.status.ErrorStatus;
 import ch.qos.logback.core.status.InfoStatus;
 import ch.qos.logback.core.status.StatusManager;
+import net.shibboleth.shared.service.LoggingService;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
@@ -43,7 +44,6 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 import net.shibboleth.utilities.java.support.resource.Resource;
 import net.shibboleth.utilities.java.support.service.AbstractReloadableService;
-import net.shibboleth.utilities.java.support.service.LoggingService;
 import net.shibboleth.utilities.java.support.service.ServiceException;
 import net.shibboleth.utilities.java.support.service.ServiceableComponent;
 
diff --git a/shib-networking/src/main/java/net/shibboleth/utilities/java/support/ddf/package-info.java b/shib-service/src/main/java/net/shibboleth/shared/service/impl/package-info.java
similarity index 66%
rename from shib-networking/src/main/java/net/shibboleth/utilities/java/support/ddf/package-info.java
rename to shib-service/src/main/java/net/shibboleth/shared/service/impl/package-info.java
index 2cf59d48..ae474308 100644
--- a/shib-networking/src/main/java/net/shibboleth/utilities/java/support/ddf/package-info.java
+++ b/shib-service/src/main/java/net/shibboleth/shared/service/impl/package-info.java
@@ -16,13 +16,6 @@
  */
 
 /**
- * Implementation of the Dynamic Dataflow abstraction used in the
- * Service Provider for interprocess communication.
- * 
- * <p>DDFs are somewhat JSON-like, but with a (subjectively) friendlier
- * API and allow for arbitrary serialization. They support dynamic RPC
- * interfaces that don't require pre-definition of a data contract or
- * compilation of client/server stubs.</p>
+ * Implementations of shared service interfaces.
  */
-
-package net.shibboleth.utilities.java.support.ddf;
\ No newline at end of file
+package net.shibboleth.shared.service.impl;
\ No newline at end of file
diff --git a/shib-support/src/main/java/net/shibboleth/utilities/java/support/velocity/package-info.java b/shib-service/src/main/java/net/shibboleth/shared/service/package-info.java
similarity index 88%
copy from shib-support/src/main/java/net/shibboleth/utilities/java/support/velocity/package-info.java
copy to shib-service/src/main/java/net/shibboleth/shared/service/package-info.java
index beb7024c..98adb97e 100644
--- a/shib-support/src/main/java/net/shibboleth/utilities/java/support/velocity/package-info.java
+++ b/shib-service/src/main/java/net/shibboleth/shared/service/package-info.java
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 
-/** Classes for working with Apache Velocity. */
-
-package net.shibboleth.utilities.java.support.velocity;
\ No newline at end of file
+/**
+ * Shared service APIs.
+ */
+package net.shibboleth.shared.service;
\ No newline at end of file
diff --git a/shib-spring/src/main/java/net/shibboleth/ext/spring/config/NonReloadableExcluder.java b/shib-service/src/main/java/net/shibboleth/shared/service/reloadable/NonReloadableExcluder.java
similarity index 97%
rename from shib-spring/src/main/java/net/shibboleth/ext/spring/config/NonReloadableExcluder.java
rename to shib-service/src/main/java/net/shibboleth/shared/service/reloadable/NonReloadableExcluder.java
index 48db622b..a92707fb 100644
--- a/shib-spring/src/main/java/net/shibboleth/ext/spring/config/NonReloadableExcluder.java
+++ b/shib-service/src/main/java/net/shibboleth/shared/service/reloadable/NonReloadableExcluder.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.ext.spring.config;
+package net.shibboleth.shared.service.reloadable;
 
 import javax.annotation.Nonnull;
 
diff --git a/shib-spring/src/main/java/net/shibboleth/ext/spring/factory/ProxiedFactoryBean.java b/shib-service/src/main/java/net/shibboleth/shared/service/reloadable/ProxiedFactoryBean.java
similarity index 99%
rename from shib-spring/src/main/java/net/shibboleth/ext/spring/factory/ProxiedFactoryBean.java
rename to shib-service/src/main/java/net/shibboleth/shared/service/reloadable/ProxiedFactoryBean.java
index 02eb2472..57e671a7 100644
--- a/shib-spring/src/main/java/net/shibboleth/ext/spring/factory/ProxiedFactoryBean.java
+++ b/shib-service/src/main/java/net/shibboleth/shared/service/reloadable/ProxiedFactoryBean.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.ext.spring.factory;
+package net.shibboleth.shared.service.reloadable;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
diff --git a/shib-spring/src/main/java/net/shibboleth/ext/spring/config/ReloadableScope.java b/shib-service/src/main/java/net/shibboleth/shared/service/reloadable/ReloadableScope.java
similarity index 98%
rename from shib-spring/src/main/java/net/shibboleth/ext/spring/config/ReloadableScope.java
rename to shib-service/src/main/java/net/shibboleth/shared/service/reloadable/ReloadableScope.java
index afdd0f5d..39aec3f0 100644
--- a/shib-spring/src/main/java/net/shibboleth/ext/spring/config/ReloadableScope.java
+++ b/shib-service/src/main/java/net/shibboleth/shared/service/reloadable/ReloadableScope.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.ext.spring.config;
+package net.shibboleth.shared.service.reloadable;
 
 import javax.annotation.Nonnull;
 
diff --git a/shib-support/src/main/java/net/shibboleth/utilities/java/support/velocity/package-info.java b/shib-service/src/main/java/net/shibboleth/shared/service/reloadable/package-info.java
similarity index 88%
copy from shib-support/src/main/java/net/shibboleth/utilities/java/support/velocity/package-info.java
copy to shib-service/src/main/java/net/shibboleth/shared/service/reloadable/package-info.java
index beb7024c..fbd3bc82 100644
--- a/shib-support/src/main/java/net/shibboleth/utilities/java/support/velocity/package-info.java
+++ b/shib-service/src/main/java/net/shibboleth/shared/service/reloadable/package-info.java
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 
-/** Classes for working with Apache Velocity. */
-
-package net.shibboleth.utilities.java.support.velocity;
\ No newline at end of file
+/**
+ * Classes related to reloading beans.
+ */
+package net.shibboleth.shared.service.reloadable;
\ No newline at end of file
diff --git a/shib-security/src/main/java/net/shibboleth/utilities/java/support/security/impl/DelegatingAccessControlService.java b/shib-service/src/main/java/net/shibboleth/shared/service/security/impl/DelegatingAccessControlService.java
similarity index 98%
rename from shib-security/src/main/java/net/shibboleth/utilities/java/support/security/impl/DelegatingAccessControlService.java
rename to shib-service/src/main/java/net/shibboleth/shared/service/security/impl/DelegatingAccessControlService.java
index aaa2b7b5..549f6d10 100644
--- a/shib-security/src/main/java/net/shibboleth/utilities/java/support/security/impl/DelegatingAccessControlService.java
+++ b/shib-service/src/main/java/net/shibboleth/shared/service/security/impl/DelegatingAccessControlService.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.utilities.java.support.security.impl;
+package net.shibboleth.shared.service.security.impl;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
diff --git a/shib-spring/src/main/java/net/shibboleth/ext/spring/service/ServiceableAccessControlService.java b/shib-service/src/main/java/net/shibboleth/shared/service/security/impl/ReloadingAccessControlService.java
similarity index 86%
copy from shib-spring/src/main/java/net/shibboleth/ext/spring/service/ServiceableAccessControlService.java
copy to shib-service/src/main/java/net/shibboleth/shared/service/security/impl/ReloadingAccessControlService.java
index f6674de3..8d1fa3aa 100644
--- a/shib-spring/src/main/java/net/shibboleth/ext/spring/service/ServiceableAccessControlService.java
+++ b/shib-service/src/main/java/net/shibboleth/shared/service/security/impl/ReloadingAccessControlService.java
@@ -15,10 +15,11 @@
  * limitations under the License.
  */
 
-package net.shibboleth.ext.spring.service;
+package net.shibboleth.shared.service.security.impl;
 
 import javax.annotation.Nonnull;
 
+import net.shibboleth.ext.spring.service.AbstractServiceableComponent;
 import net.shibboleth.utilities.java.support.annotation.ParameterName;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -29,7 +30,7 @@ import net.shibboleth.utilities.java.support.security.AccessControlService;
  * This class wraps an {@link AccessControlService} in a
  * {@link net.shibboleth.utilities.java.support.service.ServiceableComponent}.
  */
-public class ServiceableAccessControlService extends AbstractServiceableComponent<AccessControlService>
+public class ReloadingAccessControlService extends AbstractServiceableComponent<AccessControlService>
         implements AccessControlService {
 
     /** The embedded service. */
@@ -40,7 +41,7 @@ public class ServiceableAccessControlService extends AbstractServiceableComponen
      * 
      * @param svc the embedded service
      */
-    public ServiceableAccessControlService(@Nonnull @ParameterName(name="svc") final AccessControlService svc) {
+    public ReloadingAccessControlService(@Nonnull @ParameterName(name="svc") final AccessControlService svc) {
         service = Constraint.isNotNull(svc, "AccessControlService cannot be null");
     }
 
diff --git a/shib-spring/src/main/java/net/shibboleth/ext/spring/service/ServiceableAccessControlService.java b/shib-service/src/main/java/net/shibboleth/shared/service/security/impl/ServiceableAccessControlService.java
similarity index 94%
rename from shib-spring/src/main/java/net/shibboleth/ext/spring/service/ServiceableAccessControlService.java
rename to shib-service/src/main/java/net/shibboleth/shared/service/security/impl/ServiceableAccessControlService.java
index f6674de3..9920a859 100644
--- a/shib-spring/src/main/java/net/shibboleth/ext/spring/service/ServiceableAccessControlService.java
+++ b/shib-service/src/main/java/net/shibboleth/shared/service/security/impl/ServiceableAccessControlService.java
@@ -15,10 +15,11 @@
  * limitations under the License.
  */
 
-package net.shibboleth.ext.spring.service;
+package net.shibboleth.shared.service.security.impl;
 
 import javax.annotation.Nonnull;
 
+import net.shibboleth.ext.spring.service.AbstractServiceableComponent;
 import net.shibboleth.utilities.java.support.annotation.ParameterName;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.logic.Constraint;
diff --git a/shib-support/src/main/java/net/shibboleth/utilities/java/support/velocity/package-info.java b/shib-service/src/main/java/net/shibboleth/shared/service/security/impl/package-info.java
similarity index 88%
copy from shib-support/src/main/java/net/shibboleth/utilities/java/support/velocity/package-info.java
copy to shib-service/src/main/java/net/shibboleth/shared/service/security/impl/package-info.java
index beb7024c..c361c579 100644
--- a/shib-support/src/main/java/net/shibboleth/utilities/java/support/velocity/package-info.java
+++ b/shib-service/src/main/java/net/shibboleth/shared/service/security/impl/package-info.java
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 
-/** Classes for working with Apache Velocity. */
-
-package net.shibboleth.utilities.java.support.velocity;
\ No newline at end of file
+/**
+ * Security-related service implementation classes.
+ */
+package net.shibboleth.shared.service.security.impl;
\ No newline at end of file
diff --git a/shib-support/src/main/java/net/shibboleth/utilities/java/support/service/AbstractReloadableService.java b/shib-service/src/main/java/net/shibboleth/utilities/java/support/service/AbstractReloadableService.java
similarity index 100%
rename from shib-support/src/main/java/net/shibboleth/utilities/java/support/service/AbstractReloadableService.java
rename to shib-service/src/main/java/net/shibboleth/utilities/java/support/service/AbstractReloadableService.java
diff --git a/shib-support/src/main/java/net/shibboleth/utilities/java/support/service/ReloadableService.java b/shib-service/src/main/java/net/shibboleth/utilities/java/support/service/ReloadableService.java
similarity index 100%
rename from shib-support/src/main/java/net/shibboleth/utilities/java/support/service/ReloadableService.java
rename to shib-service/src/main/java/net/shibboleth/utilities/java/support/service/ReloadableService.java
diff --git a/shib-support/src/main/java/net/shibboleth/utilities/java/support/service/ReloadableServiceGaugeSet.java b/shib-service/src/main/java/net/shibboleth/utilities/java/support/service/ReloadableServiceGaugeSet.java
similarity index 100%
rename from shib-support/src/main/java/net/shibboleth/utilities/java/support/service/ReloadableServiceGaugeSet.java
rename to shib-service/src/main/java/net/shibboleth/utilities/java/support/service/ReloadableServiceGaugeSet.java
diff --git a/shib-support/src/main/java/net/shibboleth/utilities/java/support/service/ServiceException.java b/shib-service/src/main/java/net/shibboleth/utilities/java/support/service/ServiceException.java
similarity index 100%
rename from shib-support/src/main/java/net/shibboleth/utilities/java/support/service/ServiceException.java
rename to shib-service/src/main/java/net/shibboleth/utilities/java/support/service/ServiceException.java
diff --git a/shib-support/src/main/java/net/shibboleth/utilities/java/support/service/ServiceableComponent.java b/shib-service/src/main/java/net/shibboleth/utilities/java/support/service/ServiceableComponent.java
similarity index 100%
rename from shib-support/src/main/java/net/shibboleth/utilities/java/support/service/ServiceableComponent.java
rename to shib-service/src/main/java/net/shibboleth/utilities/java/support/service/ServiceableComponent.java
diff --git a/shib-support/src/main/java/net/shibboleth/utilities/java/support/service/package-info.java b/shib-service/src/main/java/net/shibboleth/utilities/java/support/service/package-info.java
similarity index 100%
rename from shib-support/src/main/java/net/shibboleth/utilities/java/support/service/package-info.java
rename to shib-service/src/main/java/net/shibboleth/utilities/java/support/service/package-info.java
diff --git a/shib-spring/src/test/java/net/shibboleth/ext/spring/service/NonReloadableTestBean.java b/shib-service/src/test/java/net/shibboleth/ext/spring/service/NonReloadableTestBean.java
similarity index 100%
rename from shib-spring/src/test/java/net/shibboleth/ext/spring/service/NonReloadableTestBean.java
rename to shib-service/src/test/java/net/shibboleth/ext/spring/service/NonReloadableTestBean.java
diff --git a/shib-spring/src/test/java/net/shibboleth/ext/spring/service/ReloadableBeanServiceTest.java b/shib-service/src/test/java/net/shibboleth/ext/spring/service/ReloadableBeanServiceTest.java
similarity index 100%
rename from shib-spring/src/test/java/net/shibboleth/ext/spring/service/ReloadableBeanServiceTest.java
rename to shib-service/src/test/java/net/shibboleth/ext/spring/service/ReloadableBeanServiceTest.java
diff --git a/shib-spring/src/test/java/net/shibboleth/ext/spring/service/ReloadableSpringServiceTest.java b/shib-service/src/test/java/net/shibboleth/ext/spring/service/ReloadableSpringServiceTest.java
similarity index 100%
rename from shib-spring/src/test/java/net/shibboleth/ext/spring/service/ReloadableSpringServiceTest.java
rename to shib-service/src/test/java/net/shibboleth/ext/spring/service/ReloadableSpringServiceTest.java
diff --git a/shib-spring/src/test/java/net/shibboleth/ext/spring/service/ReloadableTestBean.java b/shib-service/src/test/java/net/shibboleth/ext/spring/service/ReloadableTestBean.java
similarity index 100%
rename from shib-spring/src/test/java/net/shibboleth/ext/spring/service/ReloadableTestBean.java
rename to shib-service/src/test/java/net/shibboleth/ext/spring/service/ReloadableTestBean.java
diff --git a/shib-spring/src/test/java/net/shibboleth/ext/spring/service/TestServiceableComponent.java b/shib-service/src/test/java/net/shibboleth/ext/spring/service/TestServiceableComponent.java
similarity index 100%
rename from shib-spring/src/test/java/net/shibboleth/ext/spring/service/TestServiceableComponent.java
rename to shib-service/src/test/java/net/shibboleth/ext/spring/service/TestServiceableComponent.java
diff --git a/shib-spring/src/test/resources/net/shibboleth/ext/spring/service/BrokenBean1.xml b/shib-service/src/test/resources/net/shibboleth/ext/spring/service/BrokenBean1.xml
similarity index 100%
rename from shib-spring/src/test/resources/net/shibboleth/ext/spring/service/BrokenBean1.xml
rename to shib-service/src/test/resources/net/shibboleth/ext/spring/service/BrokenBean1.xml
diff --git a/shib-spring/src/test/resources/net/shibboleth/ext/spring/service/BrokenBean2.xml b/shib-service/src/test/resources/net/shibboleth/ext/spring/service/BrokenBean2.xml
similarity index 100%
rename from shib-spring/src/test/resources/net/shibboleth/ext/spring/service/BrokenBean2.xml
rename to shib-service/src/test/resources/net/shibboleth/ext/spring/service/BrokenBean2.xml
diff --git a/shib-spring/src/test/resources/net/shibboleth/ext/spring/service/ReloadableBeans1.xml b/shib-service/src/test/resources/net/shibboleth/ext/spring/service/ReloadableBeans1.xml
similarity index 93%
rename from shib-spring/src/test/resources/net/shibboleth/ext/spring/service/ReloadableBeans1.xml
rename to shib-service/src/test/resources/net/shibboleth/ext/spring/service/ReloadableBeans1.xml
index e5630a67..ecf00f9c 100644
--- a/shib-spring/src/test/resources/net/shibboleth/ext/spring/service/ReloadableBeans1.xml
+++ b/shib-service/src/test/resources/net/shibboleth/ext/spring/service/ReloadableBeans1.xml
@@ -33,7 +33,7 @@
                 <bean class="net.shibboleth.ext.spring.service.ApplicationContextServiceStrategy" />
             </constructor-arg>
             <property name="beanFactoryPostProcessors">
-                <bean class="net.shibboleth.ext.spring.config.NonReloadableExcluder" />
+                <bean class="net.shibboleth.shared.service.reloadable.NonReloadableExcluder" />
             </property>
         </bean>
 
@@ -41,7 +41,7 @@
 	        <property name="scopes">
 	            <map>
 	                <entry key="reloadable">
-	                    <bean class="net.shibboleth.ext.spring.config.ReloadableScope"
+	                    <bean class="net.shibboleth.shared.service.reloadable.ReloadableScope"
                             c:service-ref="reloadableBeanService" />
 	                </entry>
 	            </map>
diff --git a/shib-spring/src/test/resources/net/shibboleth/ext/spring/service/ReloadableSpringService.xml b/shib-service/src/test/resources/net/shibboleth/ext/spring/service/ReloadableSpringService.xml
similarity index 100%
rename from shib-spring/src/test/resources/net/shibboleth/ext/spring/service/ReloadableSpringService.xml
rename to shib-service/src/test/resources/net/shibboleth/ext/spring/service/ReloadableSpringService.xml
diff --git a/shib-spring/src/test/resources/net/shibboleth/ext/spring/service/ServiceableBean1.xml b/shib-service/src/test/resources/net/shibboleth/ext/spring/service/ServiceableBean1.xml
similarity index 100%
rename from shib-spring/src/test/resources/net/shibboleth/ext/spring/service/ServiceableBean1.xml
rename to shib-service/src/test/resources/net/shibboleth/ext/spring/service/ServiceableBean1.xml
diff --git a/shib-spring/src/test/resources/net/shibboleth/ext/spring/service/ServiceableBean2.xml b/shib-service/src/test/resources/net/shibboleth/ext/spring/service/ServiceableBean2.xml
similarity index 100%
rename from shib-spring/src/test/resources/net/shibboleth/ext/spring/service/ServiceableBean2.xml
rename to shib-service/src/test/resources/net/shibboleth/ext/spring/service/ServiceableBean2.xml
diff --git a/shib-shared-bom/pom.xml b/shib-shared-bom/pom.xml
index 41562f8a..029aeb63 100644
--- a/shib-shared-bom/pom.xml
+++ b/shib-shared-bom/pom.xml
@@ -19,6 +19,11 @@
     
     <dependencyManagement>
         <dependencies>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>shib-networking</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
                 <artifactId>shib-security</artifactId>
@@ -26,7 +31,12 @@
             </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
-                <artifactId>shib-networking</artifactId>
+                <artifactId>shib-service</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>shib-velocity</artifactId>
                 <version>${project.version}</version>
             </dependency>
 
diff --git a/shib-spring/pom.xml b/shib-spring/pom.xml
index baef8bc8..6f9c62b7 100644
--- a/shib-spring/pom.xml
+++ b/shib-spring/pom.xml
@@ -40,22 +40,23 @@
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpclient-cache</artifactId>
         </dependency>
-
+        
         <dependency>
-            <groupId>net.shibboleth.shared</groupId>
-            <artifactId>shib-security</artifactId>
-            <version>${project.version}</version>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity-engine-core</artifactId>
+            <!-- Required for Velocity Spring integration code. -->
+            <optional>true</optional>
         </dependency>
 
         <dependency>
-            <groupId>net.shibboleth.shared</groupId>
-            <artifactId>shib-networking</artifactId>
+            <groupId>net.shibboleth.utilities</groupId>
+            <artifactId>java-support</artifactId>
             <version>${project.version}</version>
         </dependency>
-
+        
         <dependency>
-            <groupId>net.shibboleth.utilities</groupId>
-            <artifactId>java-support</artifactId>
+            <groupId>net.shibboleth.shared</groupId>
+            <artifactId>shib-networking</artifactId>
             <version>${project.version}</version>
         </dependency>
 
@@ -101,12 +102,6 @@
             <!-- Required for error handling classes. -->
             <optional>true</optional>
         </dependency>
-        <dependency>
-            <groupId>org.apache.velocity</groupId>
-            <artifactId>velocity-engine-core</artifactId>
-            <!-- Required if you're using classes from the velocity package -->
-            <optional>true</optional>
-        </dependency>
         <dependency>
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-core</artifactId>
@@ -134,13 +129,6 @@
         <!-- Runtime dependencies -->
 
         <!-- Test dependencies -->
-        <dependency>
-            <groupId>net.shibboleth.shared</groupId>
-            <artifactId>shib-testing</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-        
         <dependency>
           <groupId>${spring.groupId}</groupId>
           <artifactId>spring-test</artifactId>
diff --git a/shib-spring/src/main/java/net/shibboleth/ext/spring/config/ByteArrayToDDFConverter.java b/shib-spring/src/main/java/net/shibboleth/ext/spring/config/ByteArrayToDDFConverter.java
deleted file mode 100644
index 803cedfa..00000000
--- a/shib-spring/src/main/java/net/shibboleth/ext/spring/config/ByteArrayToDDFConverter.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.ext.spring.config;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-
-import org.springframework.core.convert.converter.Converter;
-
-import net.shibboleth.utilities.java.support.ddf.DDF;
-
-/**
- * Spring converter from byte array to {@link DDF} object.
- * 
- * @since 7.0.0
- */
-public class ByteArrayToDDFConverter implements Converter<byte[], DDF> {
-
-    /** {@inheritDoc} */
-    public DDF convert(final byte[] source) {
-        try (final ByteArrayInputStream bais = new ByteArrayInputStream(source)) {
-            return DDF.deserialize(bais);
-        } catch (final IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-}
\ No newline at end of file
diff --git a/shib-spring/src/main/java/net/shibboleth/ext/spring/config/DDFToByteArrayConverter.java b/shib-spring/src/main/java/net/shibboleth/ext/spring/config/DDFToByteArrayConverter.java
deleted file mode 100644
index 617dc607..00000000
--- a/shib-spring/src/main/java/net/shibboleth/ext/spring/config/DDFToByteArrayConverter.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You under the Apache
- * License, Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.shibboleth.ext.spring.config;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-import org.springframework.core.convert.converter.Converter;
-import net.shibboleth.utilities.java.support.ddf.DDF;
-
-/**
- * Spring converter from {@link DDF} to byte array.
- * 
- * @since 7.0.0
- */
-public class DDFToByteArrayConverter implements Converter<DDF, byte[]> {
-
-    /** {@inheritDoc} */
-    public byte[] convert(final DDF source) {
-        try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
-            source.serialize(baos);
-            return baos.toByteArray();
-        } catch (final IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-}
\ No newline at end of file
diff --git a/shib-spring/src/test/java/net/shibboleth/ext/spring/resource/ConditionalResourceTest.java b/shib-spring/src/test/java/net/shibboleth/ext/spring/resource/ConditionalResourceTest.java
index 51b26115..6bc02514 100644
--- a/shib-spring/src/test/java/net/shibboleth/ext/spring/resource/ConditionalResourceTest.java
+++ b/shib-spring/src/test/java/net/shibboleth/ext/spring/resource/ConditionalResourceTest.java
@@ -23,8 +23,6 @@ import net.shibboleth.ext.spring.util.SchemaTypeAwareXMLBeanDefinitionReader;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.httpclient.HttpClientBuilder;
 import net.shibboleth.utilities.java.support.httpclient.HttpClientContextHandler;
-import net.shibboleth.utilities.java.support.testing.RepositorySupport;
-import net.shibboleth.utilities.java.support.testing.ResourceTestHelper;
 
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpUriRequest;
diff --git a/shib-spring/src/test/java/net/shibboleth/ext/spring/resource/FileBackedHTTPResourceTest.java b/shib-spring/src/test/java/net/shibboleth/ext/spring/resource/FileBackedHTTPResourceTest.java
index ba8899e5..c6286578 100644
--- a/shib-spring/src/test/java/net/shibboleth/ext/spring/resource/FileBackedHTTPResourceTest.java
+++ b/shib-spring/src/test/java/net/shibboleth/ext/spring/resource/FileBackedHTTPResourceTest.java
@@ -23,7 +23,6 @@ import java.io.IOException;
 import net.shibboleth.ext.spring.context.FilesystemGenericApplicationContext;
 import net.shibboleth.ext.spring.util.SchemaTypeAwareXMLBeanDefinitionReader;
 import net.shibboleth.utilities.java.support.httpclient.HttpClientBuilder;
-import net.shibboleth.utilities.java.support.testing.ResourceTestHelper;
 
 import org.apache.http.client.HttpClient;
 import org.springframework.context.support.GenericApplicationContext;
diff --git a/shib-spring/src/test/java/net/shibboleth/ext/spring/resource/HTTPResourceTest.java b/shib-spring/src/test/java/net/shibboleth/ext/spring/resource/HTTPResourceTest.java
index 98134b97..26c39925 100644
--- a/shib-spring/src/test/java/net/shibboleth/ext/spring/resource/HTTPResourceTest.java
+++ b/shib-spring/src/test/java/net/shibboleth/ext/spring/resource/HTTPResourceTest.java
@@ -40,7 +40,6 @@ import net.shibboleth.ext.spring.util.SchemaTypeAwareXMLBeanDefinitionReader;
 import net.shibboleth.utilities.java.support.httpclient.HttpClientBuilder;
 import net.shibboleth.utilities.java.support.httpclient.HttpClientContextHandler;
 import net.shibboleth.utilities.java.support.httpclient.InMemoryCachingHttpClientBuilder;
-import net.shibboleth.utilities.java.support.testing.ResourceTestHelper;
 
 /**
  * Test for HTTPResource.
diff --git a/shib-testing/src/main/java/net/shibboleth/utilities/java/support/testing/RepositorySupport.java b/shib-spring/src/test/java/net/shibboleth/ext/spring/resource/RepositorySupport.java
similarity index 94%
copy from shib-testing/src/main/java/net/shibboleth/utilities/java/support/testing/RepositorySupport.java
copy to shib-spring/src/test/java/net/shibboleth/ext/spring/resource/RepositorySupport.java
index f657b45d..11b4a78d 100644
--- a/shib-testing/src/main/java/net/shibboleth/utilities/java/support/testing/RepositorySupport.java
+++ b/shib-spring/src/test/java/net/shibboleth/ext/spring/resource/RepositorySupport.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.utilities.java.support.testing;
+package net.shibboleth.ext.spring.resource;
 
 import javax.annotation.Nonnull;
 
@@ -23,7 +23,11 @@ import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
-/** Support class for working with the project version control repository. */
+/**
+ * Support class for working with the project version control repository.
+ * 
+ * <p>NOTE: If this changes, change the "main" copy in shib-testing.</p>
+ */
 public final class RepositorySupport {
     
     /** Constructor. */
diff --git a/shib-testing/src/main/java/net/shibboleth/utilities/java/support/testing/ResourceTestHelper.java b/shib-spring/src/test/java/net/shibboleth/ext/spring/resource/ResourceTestHelper.java
similarity index 92%
copy from shib-testing/src/main/java/net/shibboleth/utilities/java/support/testing/ResourceTestHelper.java
copy to shib-spring/src/test/java/net/shibboleth/ext/spring/resource/ResourceTestHelper.java
index 23af217f..2fc95627 100644
--- a/shib-testing/src/main/java/net/shibboleth/utilities/java/support/testing/ResourceTestHelper.java
+++ b/shib-spring/src/test/java/net/shibboleth/ext/spring/resource/ResourceTestHelper.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.utilities.java.support.testing;
+package net.shibboleth.ext.spring.resource;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -25,7 +25,9 @@ import org.springframework.core.io.Resource;
 import com.google.common.io.Closeables;
 
 /**
- *
+ * Compares to resources for equality.
+ * 
+ * <p>NOTE: If this changes, change the "main" copy in shib-testing.</p>
  */
 @SuppressWarnings("javadoc")
 public class ResourceTestHelper {
diff --git a/shib-support/pom.xml b/shib-support/pom.xml
index 08d6a564..5095c8ab 100644
--- a/shib-support/pom.xml
+++ b/shib-support/pom.xml
@@ -31,39 +31,22 @@
             <artifactId>guava</artifactId>
         </dependency>
 
-        <!-- OPTIONAL Compile Dependencies -->
+        <!-- Provided Dependencies -->
+
+        <!-- Runtime Dependencies -->
+
+        <!-- Test Dependencies -->
         <dependency>
-            <!-- Required if you're using classes from the logging package. -->
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-classic</artifactId>
-            <scope>compile</scope><!-- normally runtime -->
-            <optional>true</optional>
+            <scope>test</scope><!-- normally runtime -->
         </dependency>
         <dependency>
-            <!-- Required if you're using classes from the logging package. -->
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-core</artifactId>
-            <scope>compile</scope><!-- normally runtime -->
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <!-- Required if you're using classes from the velocity package -->
-            <groupId>org.apache.velocity</groupId>
-            <artifactId>velocity-engine-core</artifactId>
-            <optional>true</optional>
+            <scope>test</scope><!-- normally runtime -->
         </dependency>
-        <dependency>
-            <!-- Required if using the metrics service class. -->
-            <groupId>io.dropwizard.metrics</groupId>
-            <artifactId>metrics-core</artifactId>
-            <optional>true</optional>
-        </dependency>
-
-        <!-- Provided Dependencies -->
 
-        <!-- Runtime Dependencies -->
-
-        <!-- Test Dependencies -->
         <dependency>
             <groupId>${spring.groupId}</groupId>
             <artifactId>spring-core</artifactId>
diff --git a/shib-testing/pom.xml b/shib-testing/pom.xml
index 0da90c2a..08c9026d 100644
--- a/shib-testing/pom.xml
+++ b/shib-testing/pom.xml
@@ -27,6 +27,18 @@
             <version>${project.version}</version>
         </dependency>
 
+        <dependency>
+            <groupId>net.shibboleth.ext</groupId>
+            <artifactId>spring-extensions</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>shib-service</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
         <!-- Normally test scope. -->
         <dependency>
             <groupId>org.hsqldb</groupId>
diff --git a/shib-testing/src/main/java/net/shibboleth/utilities/java/support/testing/RepositorySupport.java b/shib-testing/src/main/java/net/shibboleth/utilities/java/support/testing/RepositorySupport.java
index f657b45d..123df385 100644
--- a/shib-testing/src/main/java/net/shibboleth/utilities/java/support/testing/RepositorySupport.java
+++ b/shib-testing/src/main/java/net/shibboleth/utilities/java/support/testing/RepositorySupport.java
@@ -23,7 +23,11 @@ import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
-/** Support class for working with the project version control repository. */
+/**
+ * Support class for working with the project version control repository.
+ * 
+ * <p>NOTE: If this changes, change the "additional" copy in shib-spring.</p>
+ */
 public final class RepositorySupport {
     
     /** Constructor. */
diff --git a/shib-testing/src/main/java/net/shibboleth/utilities/java/support/testing/ResourceTestHelper.java b/shib-testing/src/main/java/net/shibboleth/utilities/java/support/testing/ResourceTestHelper.java
index 23af217f..ab850e16 100644
--- a/shib-testing/src/main/java/net/shibboleth/utilities/java/support/testing/ResourceTestHelper.java
+++ b/shib-testing/src/main/java/net/shibboleth/utilities/java/support/testing/ResourceTestHelper.java
@@ -25,7 +25,9 @@ import org.springframework.core.io.Resource;
 import com.google.common.io.Closeables;
 
 /**
- *
+ * Compare two resources for equality.
+ * 
+ * <p>NOTE: If this changes, change the "additional" copy in shib-spring.</p>
  */
 @SuppressWarnings("javadoc")
 public class ResourceTestHelper {
diff --git a/shib-testing/src/test/java/net/shibboleth/utilities/java/support/testing/RepositorySupportTest.java b/shib-testing/src/test/java/net/shibboleth/utilities/java/support/testing/RepositorySupportTest.java
index 0386ff8d..73834e70 100644
--- a/shib-testing/src/test/java/net/shibboleth/utilities/java/support/testing/RepositorySupportTest.java
+++ b/shib-testing/src/test/java/net/shibboleth/utilities/java/support/testing/RepositorySupportTest.java
@@ -7,8 +7,6 @@ import java.net.URL;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import net.shibboleth.utilities.java.support.testing.RepositorySupport;
-
 
 public class RepositorySupportTest {
 
diff --git a/shib-velocity/.check-m2 b/shib-velocity/.check-m2
new file mode 100644
index 00000000..048849a0
--- /dev/null
+++ b/shib-velocity/.check-m2
@@ -0,0 +1 @@
+This file provokes a signature check of the maven repository unless overridden by the no-check-m2 property.
\ No newline at end of file
diff --git a/shib-velocity/.checkstyle b/shib-velocity/.checkstyle
new file mode 100644
index 00000000..186d7f35
--- /dev/null
+++ b/shib-velocity/.checkstyle
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<fileset-config file-format-version="1.2.0" simple-config="false" sync-formatter="false">
+
+    <local-check-config name="Shibboleth Checkstyle" location="/java-shib-shared/resources/checkstyle/checkstyle.xml" type="project" description="">
+        <additional-data name="cache-file" value="true"/>
+        <additional-data name="cache-props-file-location" value="null_1312636288299_cache.properties"/>
+        <additional-data name="cache-file-location" value="null_1312636288299_cache.xml"/>
+    </local-check-config>
+  
+    <fileset name="main source" enabled="true" check-config-name="Shibboleth Checkstyle" local="true">
+        <file-match-pattern match-pattern="src/main/java/.*\.java$" include-pattern="true"/>
+    </fileset>
+  
+</fileset-config>
diff --git a/shib-velocity/.gitignore b/shib-velocity/.gitignore
new file mode 100644
index 00000000..d8e6f876
--- /dev/null
+++ b/shib-velocity/.gitignore
@@ -0,0 +1,21 @@
+# A simulation of Subversion default ignores, generated by reposurgeon.
+*.o
+*.lo
+*.la
+*.al
+*.libs
+*.so
+*.so.[0-9]*
+*.a
+*.pyc
+*.pyo
+*.rej
+*.iml
+*~
+*.#*
+.*.swp
+.DS_store
+# Simulated Subversion default ignores end here
+# The contents of the svn:ignore property on the branch root.
+/test-output
+/target
diff --git a/shib-testing/pom.xml b/shib-velocity/pom.xml
similarity index 69%
copy from shib-testing/pom.xml
copy to shib-velocity/pom.xml
index 0da90c2a..f1bd1c54 100644
--- a/shib-testing/pom.xml
+++ b/shib-velocity/pom.xml
@@ -10,12 +10,12 @@
         <version>9.0.0-SNAPSHOT</version>
     </parent>
 
-    <name>Shibboleth Shared :: Testing Support</name>
-    <artifactId>shib-testing</artifactId>
+    <name>Shibboleth Shared :: Velocity Support</name>
+    <artifactId>shib-velocity</artifactId>
     <packaging>jar</packaging>
 
     <properties>
-        <automatic.module.name>net.shibboleth.shared.testing</automatic.module.name>
+        <automatic.module.name>net.shibboleth.shared.velocity</automatic.module.name>
         <checkstyle.configLocation>${project.basedir}/../resources/checkstyle/checkstyle.xml</checkstyle.configLocation>
     </properties>
 
@@ -27,34 +27,14 @@
             <version>${project.version}</version>
         </dependency>
 
-        <!-- Normally test scope. -->
-        <dependency>
-            <groupId>org.hsqldb</groupId>
-            <artifactId>hsqldb</artifactId>
-            <scope>compile</scope>
-        </dependency>
-
-        <dependency>
-            <groupId>${spring.groupId}</groupId>
-            <artifactId>spring-core</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>${spring.groupId}</groupId>
-            <artifactId>spring-context</artifactId>
-        </dependency>
-
         <dependency>
             <groupId>org.apache.velocity</groupId>
             <artifactId>velocity-engine-core</artifactId>
         </dependency>
 
-        <!-- Provided Dependencies -->
-
         <!-- Runtime Dependencies -->
 
         <!-- Test Dependencies -->
-
     </dependencies>
 
     <scm>
@@ -70,5 +50,4 @@
         </site>
     </distributionManagement>
 
-
 </project>
diff --git a/shib-support/src/main/java/net/shibboleth/utilities/java/support/velocity/Template.java b/shib-velocity/src/main/java/net/shibboleth/utilities/java/support/velocity/Template.java
similarity index 100%
rename from shib-support/src/main/java/net/shibboleth/utilities/java/support/velocity/Template.java
rename to shib-velocity/src/main/java/net/shibboleth/utilities/java/support/velocity/Template.java
diff --git a/shib-support/src/main/java/net/shibboleth/utilities/java/support/velocity/package-info.java b/shib-velocity/src/main/java/net/shibboleth/utilities/java/support/velocity/package-info.java
similarity index 100%
rename from shib-support/src/main/java/net/shibboleth/utilities/java/support/velocity/package-info.java
rename to shib-velocity/src/main/java/net/shibboleth/utilities/java/support/velocity/package-info.java

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


More information about the commits mailing list