SANTUARIO-519 - Refactor ResourceResolvers


git-svn-id: https://svn.apache.org/repos/asf/santuario/xml-security-java/trunk@1872794 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMURIDereferencer.java b/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMURIDereferencer.java
index a272a33..147ca24 100644
--- a/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMURIDereferencer.java
+++ b/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMURIDereferencer.java
@@ -28,6 +28,7 @@
 import org.apache.xml.security.Init;
 import org.apache.xml.security.utils.XMLUtils;
 import org.apache.xml.security.utils.resolver.ResourceResolver;
+import org.apache.xml.security.utils.resolver.ResourceResolverContext;
 import org.apache.xml.security.signature.XMLSignatureInput;
 
 import javax.xml.crypto.*;
@@ -102,9 +103,8 @@
         }
 
         try {
-            ResourceResolver apacheResolver =
-                ResourceResolver.getInstance(uriAttr, baseURI, secVal);
-            XMLSignatureInput in = apacheResolver.resolve(uriAttr, baseURI, secVal);
+            ResourceResolverContext resContext = new ResourceResolverContext(uriAttr, baseURI, secVal);
+            XMLSignatureInput in = ResourceResolver.resolve(resContext);
             if (in.isOctetStream()) {
                 return new ApacheOctetStreamData(in);
             } else {
diff --git a/src/main/java/org/apache/xml/security/Init.java b/src/main/java/org/apache/xml/security/Init.java
index 99de54b..110aa72 100644
--- a/src/main/java/org/apache/xml/security/Init.java
+++ b/src/main/java/org/apache/xml/security/Init.java
@@ -263,7 +263,7 @@
                 if ("ResourceResolvers".equals(tag)) {
                     Element[] resolverElem =
                         XMLUtils.selectNodes(el.getFirstChild(), CONF_NS, "Resolver");
-
+                    List<String> classNames = new ArrayList<>(resolverElem.length);
                     for (Element element : resolverElem) {
                         String javaClass =
                             element.getAttributeNS(null, "JAVACLASS");
@@ -275,16 +275,9 @@
                         } else {
                             LOG.debug("Register Resolver: {}: For unknown purposes", javaClass);
                         }
-                        try {
-                            ResourceResolver.register(javaClass);
-                        } catch (Throwable e) {
-                            LOG.warn(
-                                 "Cannot register:" + javaClass
-                                 + " perhaps some needed jars are not installed",
-                                 e
-                             );
-                        }
+                        classNames.add(javaClass);
                     }
+                    ResourceResolver.registerClassNames(classNames);
                 }
 
                 if ("KeyResolver".equals(tag)){
diff --git a/src/main/java/org/apache/xml/security/encryption/XMLCipherInput.java b/src/main/java/org/apache/xml/security/encryption/XMLCipherInput.java
index feafe99..23a9308 100644
--- a/src/main/java/org/apache/xml/security/encryption/XMLCipherInput.java
+++ b/src/main/java/org/apache/xml/security/encryption/XMLCipherInput.java
@@ -23,6 +23,7 @@
 import org.apache.xml.security.c14n.CanonicalizationException;
 import org.apache.xml.security.utils.XMLUtils;
 import org.apache.xml.security.utils.resolver.ResourceResolver;
+import org.apache.xml.security.utils.resolver.ResourceResolverContext;
 import org.apache.xml.security.utils.resolver.ResourceResolverException;
 import org.apache.xml.security.signature.XMLSignatureInput;
 import org.apache.xml.security.transforms.TransformationException;
@@ -123,9 +124,9 @@
             XMLSignatureInput input = null;
 
             try {
-                ResourceResolver resolver =
-                    ResourceResolver.getInstance(uriAttr, null, secureValidation);
-                input = resolver.resolve(uriAttr, null, secureValidation);
+                ResourceResolverContext resolverContext =
+                    new ResourceResolverContext(uriAttr, null, secureValidation);
+                input = ResourceResolver.resolve(resolverContext);
             } catch (ResourceResolverException ex) {
                 throw new XMLEncryptionException(ex);
             }
diff --git a/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolver.java b/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolver.java
index 8ff2058..4bcded1 100644
--- a/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolver.java
+++ b/src/main/java/org/apache/xml/security/keys/keyresolver/KeyResolver.java
@@ -24,6 +24,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -54,6 +55,8 @@
 
     private static List<KeyResolverSpi> resolverList = new CopyOnWriteArrayList<>();
 
+    private static final AtomicBoolean defaultResolversAdded = new AtomicBoolean();
+
     /**
      * Method length
      *
@@ -259,21 +262,23 @@
      * This method registers the default resolvers.
      */
     public static void registerDefaultResolvers() {
+        // Add a guard so that we don't repeatedly add the default resolvers
+        if (defaultResolversAdded.compareAndSet(false, true)) {
+            List<KeyResolverSpi> keyResolverList = new ArrayList<>();
+            keyResolverList.add(new RSAKeyValueResolver());
+            keyResolverList.add(new DSAKeyValueResolver());
+            keyResolverList.add(new X509CertificateResolver());
+            keyResolverList.add(new X509SKIResolver());
+            keyResolverList.add(new RetrievalMethodResolver());
+            keyResolverList.add(new X509SubjectNameResolver());
+            keyResolverList.add(new X509IssuerSerialResolver());
+            keyResolverList.add(new DEREncodedKeyValueResolver());
+            keyResolverList.add(new KeyInfoReferenceResolver());
+            keyResolverList.add(new X509DigestResolver());
+            keyResolverList.add(new ECKeyValueResolver());
 
-        List<KeyResolverSpi> keyResolverList = new ArrayList<>();
-        keyResolverList.add(new RSAKeyValueResolver());
-        keyResolverList.add(new DSAKeyValueResolver());
-        keyResolverList.add(new X509CertificateResolver());
-        keyResolverList.add(new X509SKIResolver());
-        keyResolverList.add(new RetrievalMethodResolver());
-        keyResolverList.add(new X509SubjectNameResolver());
-        keyResolverList.add(new X509IssuerSerialResolver());
-        keyResolverList.add(new DEREncodedKeyValueResolver());
-        keyResolverList.add(new KeyInfoReferenceResolver());
-        keyResolverList.add(new X509DigestResolver());
-        keyResolverList.add(new ECKeyValueResolver());
-
-        resolverList.addAll(keyResolverList);
+            resolverList.addAll(keyResolverList);
+        }
     }
 
     /**
diff --git a/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/KeyInfoReferenceResolver.java b/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/KeyInfoReferenceResolver.java
index f47368a..269890f 100644
--- a/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/KeyInfoReferenceResolver.java
+++ b/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/KeyInfoReferenceResolver.java
@@ -38,6 +38,7 @@
 import org.apache.xml.security.utils.Constants;
 import org.apache.xml.security.utils.XMLUtils;
 import org.apache.xml.security.utils.resolver.ResourceResolver;
+import org.apache.xml.security.utils.resolver.ResourceResolverContext;
 import org.w3c.dom.Attr;
 import org.w3c.dom.Element;
 import org.xml.sax.SAXException;
@@ -200,8 +201,8 @@
      */
     private XMLSignatureInput resolveInput(Attr uri, String baseURI, boolean secureValidation)
         throws XMLSecurityException {
-        ResourceResolver resRes = ResourceResolver.getInstance(uri, baseURI, secureValidation);
-        return resRes.resolve(uri, baseURI, secureValidation);
+        ResourceResolverContext resContext = new ResourceResolverContext(uri, baseURI, secureValidation);
+        return ResourceResolver.resolve(resContext);
     }
 
     /**
diff --git a/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java b/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java
index 73ac653..79d23ee 100644
--- a/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java
+++ b/src/main/java/org/apache/xml/security/keys/keyresolver/implementations/RetrievalMethodResolver.java
@@ -47,6 +47,7 @@
 import org.apache.xml.security.utils.Constants;
 import org.apache.xml.security.utils.XMLUtils;
 import org.apache.xml.security.utils.resolver.ResourceResolver;
+import org.apache.xml.security.utils.resolver.ResourceResolverContext;
 import org.w3c.dom.Attr;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -263,8 +264,8 @@
         Attr uri = rm.getURIAttr();
         // Apply the transforms
         Transforms transforms = rm.getTransforms();
-        ResourceResolver resRes = ResourceResolver.getInstance(uri, baseURI, secureValidation);
-        XMLSignatureInput resource = resRes.resolve(uri, baseURI, secureValidation);
+        ResourceResolverContext resContext = new ResourceResolverContext(uri, baseURI, secureValidation);
+        XMLSignatureInput resource = ResourceResolver.resolve(resContext);
         if (transforms != null) {
             LOG.debug("We have Transforms");
             resource = transforms.performTransforms(resource);
diff --git a/src/main/java/org/apache/xml/security/signature/Manifest.java b/src/main/java/org/apache/xml/security/signature/Manifest.java
index 2e60de9..33d175c 100644
--- a/src/main/java/org/apache/xml/security/signature/Manifest.java
+++ b/src/main/java/org/apache/xml/security/signature/Manifest.java
@@ -39,7 +39,6 @@
 import org.apache.xml.security.utils.I18n;
 import org.apache.xml.security.utils.SignatureElementProxy;
 import org.apache.xml.security.utils.XMLUtils;
-import org.apache.xml.security.utils.resolver.ResourceResolver;
 import org.apache.xml.security.utils.resolver.ResourceResolverSpi;
 import org.w3c.dom.Attr;
 import org.w3c.dom.DOMException;
@@ -78,7 +77,7 @@
     private Map<String, String> resolverProperties;
 
     /** Field perManifestResolvers */
-    private List<ResourceResolver> perManifestResolvers;
+    private List<ResourceResolverSpi> perManifestResolvers;
 
     private boolean secureValidation;
 
@@ -466,10 +465,10 @@
      * Adds Resource Resolver for retrieving resources at specified <code>URI</code> attribute
      * in <code>reference</code> element
      *
-     * @param resolver {@link ResourceResolver} can provide the implementation subclass of
+     * @param resolver {@link ResourceResolverSpi} can provide the implementation subclass of
      * {@link ResourceResolverSpi} for retrieving resource.
      */
-    public void addResourceResolver(ResourceResolver resolver) {
+    public void addResourceResolver(ResourceResolverSpi resolver) {
         if (resolver == null) {
             return;
         }
@@ -480,27 +479,10 @@
     }
 
     /**
-     * Adds Resource Resolver for retrieving resources at specified <code>URI</code> attribute
-     * in <code>reference</code> element
-     *
-     * @param resolverSpi the implementation subclass of {@link ResourceResolverSpi} for
-     * retrieving the resource.
-     */
-    public void addResourceResolver(ResourceResolverSpi resolverSpi) {
-        if (resolverSpi == null) {
-            return;
-        }
-        if (perManifestResolvers == null) {
-            perManifestResolvers = new ArrayList<>();
-        }
-        perManifestResolvers.add(new ResourceResolver(resolverSpi));
-    }
-
-    /**
      * Get the Per-Manifest Resolver List
      * @return the per-manifest Resolver List
      */
-    public List<ResourceResolver> getPerManifestResolvers() {
+    public List<ResourceResolverSpi> getPerManifestResolvers() {
         return perManifestResolvers;
     }
 
diff --git a/src/main/java/org/apache/xml/security/signature/Reference.java b/src/main/java/org/apache/xml/security/signature/Reference.java
index e9f2834..83f428d 100644
--- a/src/main/java/org/apache/xml/security/signature/Reference.java
+++ b/src/main/java/org/apache/xml/security/signature/Reference.java
@@ -46,6 +46,7 @@
 import org.apache.xml.security.utils.UnsyncBufferedOutputStream;
 import org.apache.xml.security.utils.XMLUtils;
 import org.apache.xml.security.utils.resolver.ResourceResolver;
+import org.apache.xml.security.utils.resolver.ResourceResolverContext;
 import org.apache.xml.security.utils.resolver.ResourceResolverException;
 import org.w3c.dom.Attr;
 import org.w3c.dom.Document;
@@ -416,13 +417,11 @@
             Attr uriAttr =
                 getElement().getAttributeNodeNS(null, Constants._ATT_URI);
 
-            ResourceResolver resolver =
-                ResourceResolver.getInstance(
-                    uriAttr, this.baseURI, this.manifest.getPerManifestResolvers(), secureValidation
-                );
-            resolver.addProperties(this.manifest.getResolverProperties());
+            ResourceResolverContext resolverContext =
+                new ResourceResolverContext(uriAttr, this.baseURI,
+                    secureValidation, this.manifest.getResolverProperties());
 
-            return resolver.resolve(uriAttr, this.baseURI, secureValidation);
+            return ResourceResolver.resolve(this.manifest.getPerManifestResolvers(), resolverContext);
         }  catch (ResourceResolverException ex) {
             throw new ReferenceNotInitializedException(ex);
         }
diff --git a/src/main/java/org/apache/xml/security/signature/XMLSignature.java b/src/main/java/org/apache/xml/security/signature/XMLSignature.java
index bedd313..edd0777 100644
--- a/src/main/java/org/apache/xml/security/signature/XMLSignature.java
+++ b/src/main/java/org/apache/xml/security/signature/XMLSignature.java
@@ -41,7 +41,6 @@
 import org.apache.xml.security.utils.SignerOutputStream;
 import org.apache.xml.security.utils.UnsyncBufferedOutputStream;
 import org.apache.xml.security.utils.XMLUtils;
-import org.apache.xml.security.utils.resolver.ResourceResolver;
 import org.apache.xml.security.utils.resolver.ResourceResolverSpi;
 import org.w3c.dom.Attr;
 import org.w3c.dom.Document;
@@ -790,15 +789,6 @@
     }
 
     /**
-     * Adds a {@link ResourceResolver} to enable the retrieval of resources.
-     *
-     * @param resolver
-     */
-    public void addResourceResolver(ResourceResolver resolver) {
-        this.getSignedInfo().addResourceResolver(resolver);
-    }
-
-    /**
      * Adds a {@link ResourceResolverSpi} to enable the retrieval of resources.
      *
      * @param resolver
diff --git a/src/main/java/org/apache/xml/security/utils/resolver/ResourceResolver.java b/src/main/java/org/apache/xml/security/utils/resolver/ResourceResolver.java
index 3bbdbbf..f3de97b 100644
--- a/src/main/java/org/apache/xml/security/utils/resolver/ResourceResolver.java
+++ b/src/main/java/org/apache/xml/security/utils/resolver/ResourceResolver.java
@@ -20,7 +20,8 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.xml.security.signature.XMLSignatureInput;
 import org.apache.xml.security.utils.ClassLoaderUtils;
@@ -29,7 +30,6 @@
 import org.apache.xml.security.utils.resolver.implementations.ResolverFragment;
 import org.apache.xml.security.utils.resolver.implementations.ResolverLocalFilesystem;
 import org.apache.xml.security.utils.resolver.implementations.ResolverXPointer;
-import org.w3c.dom.Attr;
 
 /**
  * During reference validation, we have to retrieve resources from somewhere.
@@ -43,67 +43,128 @@
         org.slf4j.LoggerFactory.getLogger(ResourceResolver.class);
 
     /** these are the system-wide resolvers */
-    private static final List<ResourceResolver> resolverList = new ArrayList<>();
+    private static final List<ResourceResolverSpi> resolverList = new CopyOnWriteArrayList<>();
 
-    /** Field resolverSpi */
-    private final ResourceResolverSpi resolverSpi;
+    private static final AtomicBoolean defaultResolversAdded = new AtomicBoolean();
 
     /**
-     * Constructor ResourceResolver
+     * Registers a ResourceResolverSpi class.
      *
-     * @param resourceResolver
+     * @param className the name of the ResourceResolverSpi class to be registered
+     * @throws InstantiationException
+     * @throws IllegalAccessException
+     * @throws ClassNotFoundException
+     * @throws SecurityException if a security manager is installed and the
+     *    caller does not have permission to register a resource resolver
      */
-    public ResourceResolver(ResourceResolverSpi resourceResolver) {
-        this.resolverSpi = resourceResolver;
+    @SuppressWarnings("unchecked")
+    public static void register(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+        JavaUtils.checkRegisterPermission();
+        Class<ResourceResolverSpi> resourceResolverClass =
+            (Class<ResourceResolverSpi>)
+            ClassLoaderUtils.loadClass(className, ResourceResolver.class);
+        register(resourceResolverClass.newInstance(), false);
     }
 
     /**
-     * Method getInstance
+     * Registers a ResourceResolverSpi class at the beginning of the provider list.
      *
-     * @param uriAttr
-     * @param baseURI
-     * @param secureValidation
-     * @return the instance
+     * @param className the name of the ResourceResolverSpi class to be registered
+     * @throws InstantiationException
+     * @throws IllegalAccessException
+     * @throws ClassNotFoundException
+     * @throws SecurityException if a security manager is installed and the
+     *    caller does not have permission to register a resource resolver
+     */
+    @SuppressWarnings("unchecked")
+    public static void registerAtStart(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+        JavaUtils.checkRegisterPermission();
+        Class<ResourceResolverSpi> resourceResolverClass =
+            (Class<ResourceResolverSpi>)
+            ClassLoaderUtils.loadClass(className, ResourceResolver.class);
+        register(resourceResolverClass.newInstance(), true);
+    }
+
+    /**
+     * Registers a ResourceResolverSpi instance.
+     * @param resourceResolverSpi
+     * @param start
+     * @throws SecurityException if a security manager is installed and the
+     *    caller does not have permission to register a resource resolver
+     */
+    public static void register(ResourceResolverSpi resourceResolverSpi, boolean start) {
+        JavaUtils.checkRegisterPermission();
+        if (start) {
+            resolverList.add(0, resourceResolverSpi);
+        } else {
+            resolverList.add(resourceResolverSpi);
+        }
+        LOG.debug("Registered resolver: {}", resourceResolverSpi.toString());
+    }
+
+    /**
+     * Registers a list of ResourceResolverSpi classes.
+     *
+     * @param classNames
+     * @throws InstantiationException
+     * @throws IllegalAccessException
+     * @throws ClassNotFoundException
+     * @throws SecurityException if a security manager is installed and the
+     *    caller does not have permission to register the key resolver
+     */
+    public static void registerClassNames(List<String> classNames)
+        throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+        JavaUtils.checkRegisterPermission();
+
+        List<ResourceResolverSpi> resourceResolversToAdd = new ArrayList<>(classNames.size());
+        for (String className : classNames) {
+            ResourceResolverSpi resourceResolverSpi =
+                (ResourceResolverSpi)ClassLoaderUtils.loadClass(className, ResourceResolver.class).newInstance();
+            resourceResolversToAdd.add(resourceResolverSpi);
+        }
+        resolverList.addAll(resourceResolversToAdd);
+    }
+
+    /**
+     * This method registers the default resolvers.
+     */
+    public static void registerDefaultResolvers() {
+        // Add a guard so that we don't repeatedly add the default resolvers
+        if (defaultResolversAdded.compareAndSet(false, true)) {
+            List<ResourceResolverSpi> resourceResolversToAdd = new ArrayList<>();
+            resourceResolversToAdd.add(new ResolverFragment());
+            resourceResolversToAdd.add(new ResolverLocalFilesystem());
+            resourceResolversToAdd.add(new ResolverXPointer());
+            resourceResolversToAdd.add(new ResolverDirectHTTP());
+
+            resolverList.addAll(resourceResolversToAdd);
+        }
+    }
+
+    /**
+     * Method resolve
+     *
+     * @param context
+     * @return the resource
      *
      * @throws ResourceResolverException
      */
-    public static final ResourceResolver getInstance(
-        Attr uriAttr, String baseURI, boolean secureValidation
-    ) throws ResourceResolverException {
-        ResourceResolverContext context = new ResourceResolverContext(uriAttr, baseURI, secureValidation);
-        return internalGetInstance(context);
-    }
+    public static XMLSignatureInput resolve(ResourceResolverContext context)
+        throws ResourceResolverException {
+        for (ResourceResolverSpi resolver : resolverList) {
+            LOG.debug("check resolvability by class {}", resolver.getClass().getName());
 
-    private static <N> ResourceResolver internalGetInstance(ResourceResolverContext context)
-            throws ResourceResolverException {
-        synchronized (resolverList) {
-            for (ResourceResolver resolver : resolverList) {
-                ResourceResolver resolverTmp = resolver;
-                if (!resolver.resolverSpi.engineIsThreadSafe()) {
-                    try {
-                        resolverTmp =
-                            new ResourceResolver(resolver.resolverSpi.getClass().newInstance());
-                    } catch (InstantiationException e) {
-                        throw new ResourceResolverException(e, context.uriToResolve, context.baseUri, "");
-                    } catch (IllegalAccessException e) {
-                        throw new ResourceResolverException(e, context.uriToResolve, context.baseUri, "");
-                    }
+            if (resolver.engineCanResolveURI(context)) {
+                // Check to see whether the Resolver is allowed
+                if (context.secureValidation
+                    && (resolver instanceof ResolverLocalFilesystem
+                        || resolver instanceof ResolverDirectHTTP)) {
+                    Object[] exArgs = { resolver.getClass().getName() };
+                    throw new ResourceResolverException(
+                        "signature.Reference.ForbiddenResolver", exArgs, context.uriToResolve, context.baseUri
+                    );
                 }
-
-                LOG.debug("check resolvability by class {}", resolverTmp.getClass().getName());
-
-                if (resolverTmp.canResolve(context)) {
-                    // Check to see whether the Resolver is allowed
-                    if (context.secureValidation
-                        && (resolverTmp.resolverSpi instanceof ResolverLocalFilesystem
-                            || resolverTmp.resolverSpi instanceof ResolverDirectHTTP)) {
-                        Object[] exArgs = { resolverTmp.resolverSpi.getClass().getName() };
-                        throw new ResourceResolverException(
-                            "signature.Reference.ForbiddenResolver", exArgs, context.uriToResolve, context.baseUri
-                        );
-                    }
-                    return resolverTmp;
-                }
+                return resolver.engineResolveURI(context);
             }
         }
 
@@ -114,225 +175,34 @@
     }
 
     /**
-     * Method getInstance
+     * Method resolve
      *
-     * @param uri
-     * @param baseURI
      * @param individualResolvers
-     * @return the instance
+     * @param context
+     * @return the resource
      *
      * @throws ResourceResolverException
      */
-    public static ResourceResolver getInstance(
-        Attr uri, String baseURI, List<ResourceResolver> individualResolvers
-    ) throws ResourceResolverException {
-        return getInstance(uri, baseURI, individualResolvers, true);
-    }
-
-    /**
-     * Method getInstance
-     *
-     * @param uri
-     * @param baseURI
-     * @param individualResolvers
-     * @param secureValidation
-     * @return the instance
-     *
-     * @throws ResourceResolverException
-     */
-    public static ResourceResolver getInstance(
-        Attr uri, String baseURI, List<ResourceResolver> individualResolvers, boolean secureValidation
+    public static XMLSignatureInput resolve(
+        List<ResourceResolverSpi> individualResolvers, ResourceResolverContext context
     ) throws ResourceResolverException {
         LOG.debug(
             "I was asked to create a ResourceResolver and got {}",
             individualResolvers == null ? 0 : individualResolvers.size()
         );
 
-        ResourceResolverContext context = new ResourceResolverContext(uri, baseURI, secureValidation);
-
         // first check the individual Resolvers
         if (individualResolvers != null) {
-            for (int i = 0; i < individualResolvers.size(); i++) {
-                ResourceResolver resolver = individualResolvers.get(i);
+            for (ResourceResolverSpi resolver : individualResolvers) {
+                String currentClass = resolver.getClass().getName();
+                LOG.debug("check resolvability by class {}", currentClass);
 
-                if (resolver != null) {
-                    String currentClass = resolver.resolverSpi.getClass().getName();
-                    LOG.debug("check resolvability by class {}", currentClass);
-
-                    if (resolver.canResolve(context)) {
-                        return resolver;
-                    }
+                if (resolver.engineCanResolveURI(context)) {
+                    return resolver.engineResolveURI(context);
                 }
             }
         }
 
-        return internalGetInstance(context);
-    }
-
-    /**
-     * Registers a ResourceResolverSpi class. This method LOGs a warning if
-     * the class cannot be registered.
-     *
-     * @param className the name of the ResourceResolverSpi class to be registered
-     * @throws SecurityException if a security manager is installed and the
-     *    caller does not have permission to register a resource resolver
-     */
-    @SuppressWarnings("unchecked")
-    public static void register(String className) {
-        JavaUtils.checkRegisterPermission();
-        try {
-            Class<ResourceResolverSpi> resourceResolverClass =
-                (Class<ResourceResolverSpi>)
-                ClassLoaderUtils.loadClass(className, ResourceResolver.class);
-            register(resourceResolverClass, false);
-        } catch (ClassNotFoundException e) {
-            LOG.warn("Error loading resolver " + className + " disabling it");
-        }
-    }
-
-    /**
-     * Registers a ResourceResolverSpi class at the beginning of the provider
-     * list. This method LOGs a warning if the class cannot be registered.
-     *
-     * @param className the name of the ResourceResolverSpi class to be registered
-     * @throws SecurityException if a security manager is installed and the
-     *    caller does not have permission to register a resource resolver
-     */
-    @SuppressWarnings("unchecked")
-    public static void registerAtStart(String className) {
-        JavaUtils.checkRegisterPermission();
-        try {
-            Class<ResourceResolverSpi> resourceResolverClass =
-                (Class<ResourceResolverSpi>)
-                ClassLoaderUtils.loadClass(className, ResourceResolver.class);
-            register(resourceResolverClass, true);
-        } catch (ClassNotFoundException e) {
-            LOG.warn("Error loading resolver " + className + " disabling it");
-        }
-    }
-
-    /**
-     * Registers a ResourceResolverSpi class. This method LOGs a warning if the class
-     * cannot be registered.
-     * @param className
-     * @param start
-     * @throws SecurityException if a security manager is installed and the
-     *    caller does not have permission to register a resource resolver
-     */
-    public static void register(Class<? extends ResourceResolverSpi> className, boolean start) {
-        JavaUtils.checkRegisterPermission();
-        try {
-            ResourceResolverSpi resourceResolverSpi = className.newInstance();
-            register(resourceResolverSpi, start);
-        } catch (IllegalAccessException e) {
-            LOG.warn("Error loading resolver " + className + " disabling it");
-        } catch (InstantiationException e) {
-            LOG.warn("Error loading resolver " + className + " disabling it");
-        }
-    }
-
-    /**
-     * Registers a ResourceResolverSpi instance. This method LOGs a warning if the class
-     * cannot be registered.
-     * @param resourceResolverSpi
-     * @param start
-     * @throws SecurityException if a security manager is installed and the
-     *    caller does not have permission to register a resource resolver
-     */
-    public static void register(ResourceResolverSpi resourceResolverSpi, boolean start) {
-        JavaUtils.checkRegisterPermission();
-        synchronized(resolverList) {
-            if (start) {
-                resolverList.add(0, new ResourceResolver(resourceResolverSpi));
-            } else {
-                resolverList.add(new ResourceResolver(resourceResolverSpi));
-            }
-        }
-        LOG.debug("Registered resolver: {}", resourceResolverSpi.toString());
-    }
-
-    /**
-     * This method registers the default resolvers.
-     */
-    public static void registerDefaultResolvers() {
-        synchronized(resolverList) {
-            resolverList.add(new ResourceResolver(new ResolverFragment()));
-            resolverList.add(new ResourceResolver(new ResolverLocalFilesystem()));
-            resolverList.add(new ResourceResolver(new ResolverXPointer()));
-            resolverList.add(new ResourceResolver(new ResolverDirectHTTP()));
-        }
-    }
-
-    /**
-     * Method resolve
-     *
-     * @param uri
-     * @param baseURI
-     * @return the resource
-     *
-     * @throws ResourceResolverException
-     */
-    public XMLSignatureInput resolve(Attr uri, String baseURI, boolean secureValidation)
-        throws ResourceResolverException {
-        ResourceResolverContext context = new ResourceResolverContext(uri, baseURI, secureValidation);
-        return resolverSpi.engineResolveURI(context);
-    }
-
-    /**
-     * Method setProperty
-     *
-     * @param key
-     * @param value
-     */
-    public void setProperty(String key, String value) {
-        resolverSpi.engineSetProperty(key, value);
-    }
-
-    /**
-     * Method getProperty
-     *
-     * @param key
-     * @return the value of the property
-     */
-    public String getProperty(String key) {
-        return resolverSpi.engineGetProperty(key);
-    }
-
-    /**
-     * Method addProperties
-     *
-     * @param properties
-     */
-    public void addProperties(Map<String, String> properties) {
-        resolverSpi.engineAddProperies(properties);
-    }
-
-    /**
-     * Method getPropertyKeys
-     *
-     * @return all property keys.
-     */
-    public String[] getPropertyKeys() {
-        return resolverSpi.engineGetPropertyKeys();
-    }
-
-    /**
-     * Method understandsProperty
-     *
-     * @param propertyToTest
-     * @return true if the resolver understands the property
-     */
-    public boolean understandsProperty(String propertyToTest) {
-        return resolverSpi.understandsProperty(propertyToTest);
-    }
-
-    /**
-     * Method canResolve
-     *
-     * @param context
-     * @return true if it can resolve the uri
-     */
-    private boolean canResolve(ResourceResolverContext context) {
-        return this.resolverSpi.engineCanResolveURI(context);
+        return resolve(context);
     }
 }
diff --git a/src/main/java/org/apache/xml/security/utils/resolver/ResourceResolverContext.java b/src/main/java/org/apache/xml/security/utils/resolver/ResourceResolverContext.java
index ac65bde..f584401 100644
--- a/src/main/java/org/apache/xml/security/utils/resolver/ResourceResolverContext.java
+++ b/src/main/java/org/apache/xml/security/utils/resolver/ResourceResolverContext.java
@@ -18,16 +18,14 @@
  */
 package org.apache.xml.security.utils.resolver;
 
+import java.util.Collections;
+import java.util.Map;
+
 import org.w3c.dom.Attr;
 
 public class ResourceResolverContext {
 
-    public ResourceResolverContext(Attr attr, String baseUri, boolean secureValidation) {
-        this.attr = attr;
-        this.baseUri = baseUri;
-        this.secureValidation = secureValidation;
-        this.uriToResolve = attr != null ? attr.getValue() : null;
-    }
+    private final Map<String, String> properties;
 
     public final String uriToResolve;
 
@@ -36,4 +34,21 @@
     public final String baseUri;
 
     public final Attr attr;
+
+    public ResourceResolverContext(Attr attr, String baseUri, boolean secureValidation) {
+        this(attr, baseUri, secureValidation, Collections.emptyMap());
+    }
+
+    public ResourceResolverContext(Attr attr, String baseUri, boolean secureValidation, Map<String, String> properties) {
+        this.attr = attr;
+        this.baseUri = baseUri;
+        this.secureValidation = secureValidation;
+        this.uriToResolve = attr != null ? attr.getValue() : null;
+        this.properties = Collections.unmodifiableMap(properties != null ? properties : Collections.emptyMap());
+    }
+
+    public Map<String, String> getProperties() {
+        return properties;
+    }
+
 }
diff --git a/src/main/java/org/apache/xml/security/utils/resolver/ResourceResolverSpi.java b/src/main/java/org/apache/xml/security/utils/resolver/ResourceResolverSpi.java
index 9ddfa65..bdd38fd 100644
--- a/src/main/java/org/apache/xml/security/utils/resolver/ResourceResolverSpi.java
+++ b/src/main/java/org/apache/xml/security/utils/resolver/ResourceResolverSpi.java
@@ -18,23 +18,15 @@
  */
 package org.apache.xml.security.utils.resolver;
 
-import java.util.HashMap;
-import java.util.Map;
-
 import org.apache.xml.security.signature.XMLSignatureInput;
 
 /**
  * During reference validation, we have to retrieve resources from somewhere.
  *
+ * Extensions of this class must be thread-safe.
  */
 public abstract class ResourceResolverSpi {
 
-    private static final org.slf4j.Logger LOG =
-        org.slf4j.LoggerFactory.getLogger(ResourceResolverSpi.class);
-
-    /** Field properties */
-    protected Map<String, String> properties;
-
     /**
      * This is the workhorse method used to resolve resources.
      * @param context Context to use to resolve resources.
@@ -47,55 +39,6 @@
         throws ResourceResolverException;
 
     /**
-     * Method engineSetProperty
-     *
-     * @param key
-     * @param value
-     */
-    public void engineSetProperty(String key, String value) {
-        if (properties == null) {
-            properties = new HashMap<>();
-        }
-        properties.put(key, value);
-    }
-
-    /**
-     * Method engineGetProperty
-     *
-     * @param key
-     * @return the value of the property
-     */
-    public String engineGetProperty(String key) {
-        if (properties == null) {
-            return null;
-        }
-        return properties.get(key);
-    }
-
-    /**
-     *
-     * @param newProperties
-     */
-    public void engineAddProperies(Map<String, String> newProperties) {
-        if (newProperties != null && !newProperties.isEmpty()) {
-            if (properties == null) {
-                properties = new HashMap<>();
-            }
-            properties.putAll(newProperties);
-        }
-    }
-
-    /**
-     * Tells if the implementation does can be reused by several threads safely.
-     * It normally means that the implementation does not have any member, or there is
-     * member change between engineCanResolve and engineResolve invocations. Or it maintains all
-     * member info in ThreadLocal methods.
-     */
-    public boolean engineIsThreadSafe() {
-        return false;
-    }
-
-    /**
      * This method helps the {@link ResourceResolver} to decide whether a
      * {@link ResourceResolverSpi} is able to perform the requested action.
      *
@@ -104,78 +47,4 @@
      */
     public abstract boolean engineCanResolveURI(ResourceResolverContext context);
 
-    /**
-     * Method engineGetPropertyKeys
-     *
-     * @return the property keys
-     */
-    public String[] engineGetPropertyKeys() {
-        return new String[0];
-    }
-
-    /**
-     * Method understandsProperty
-     *
-     * @param propertyToTest
-     * @return true if understands the property
-     */
-    public boolean understandsProperty(String propertyToTest) {
-        String[] understood = this.engineGetPropertyKeys();
-
-        if (understood != null) {
-            for (String str : understood) {
-                if (str.equals(propertyToTest)) {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-
-    /**
-     * Fixes a platform dependent filename to standard URI form.
-     *
-     * @param str The string to fix.
-     *
-     * @return Returns the fixed URI string.
-     */
-    public static String fixURI(String str) {
-
-        // handle platform dependent strings
-        str = str.replace(java.io.File.separatorChar, '/');
-
-        if (str.length() >= 4) {
-
-            // str =~ /^\W:\/([^/])/ # to speak perl ;-))
-            char ch0 = Character.toUpperCase(str.charAt(0));
-            char ch1 = str.charAt(1);
-            char ch2 = str.charAt(2);
-            char ch3 = str.charAt(3);
-            boolean isDosFilename = 'A' <= ch0 && ch0 <= 'Z'
-                && ch1 == ':' && ch2 == '/'
-                && ch3 != '/';
-
-            if (isDosFilename) {
-                LOG.debug("Found DOS filename: {}", str);
-            }
-        }
-
-        // Windows fix
-        if (str.length() >= 2) {
-            char ch1 = str.charAt(1);
-
-            if (ch1 == ':') {
-                char ch0 = Character.toUpperCase(str.charAt(0));
-
-                if ('A' <= ch0 && ch0 <= 'Z') {
-                    str = "/" + str;
-                }
-            }
-        }
-
-        // done
-        return str;
-    }
 }
diff --git a/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverAnonymous.java b/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverAnonymous.java
index ad7c779..d8b0c04 100644
--- a/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverAnonymous.java
+++ b/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverAnonymous.java
@@ -19,49 +19,47 @@
 
 package org.apache.xml.security.utils.resolver.implementations;
 
-import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.io.InputStream;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.nio.file.Paths;
 
 import org.apache.xml.security.signature.XMLSignatureInput;
 import org.apache.xml.security.utils.resolver.ResourceResolverContext;
+import org.apache.xml.security.utils.resolver.ResourceResolverException;
 import org.apache.xml.security.utils.resolver.ResourceResolverSpi;
 
 /**
  */
 public class ResolverAnonymous extends ResourceResolverSpi {
 
-    private InputStream inStream;
-
-    @Override
-    public boolean engineIsThreadSafe() {
-        return true;
-    }
+    private final Path resourcePath;
 
     /**
      * @param filename
-     * @throws FileNotFoundException
      * @throws IOException
      */
-    public ResolverAnonymous(String filename) throws FileNotFoundException, IOException {
-        inStream = Files.newInputStream(Paths.get(filename));
+    public ResolverAnonymous(String filename) throws IOException {
+        this(Paths.get(filename));
     }
 
     /**
-     * @param is
+     * @param resourcePath
      */
-    public ResolverAnonymous(InputStream is) {
-        inStream = is;
+    public ResolverAnonymous(Path resourcePath) {
+        this.resourcePath = resourcePath;
     }
 
     /** {@inheritDoc} */
     @Override
-    public XMLSignatureInput engineResolveURI(ResourceResolverContext context) {
-        XMLSignatureInput input = new XMLSignatureInput(inStream);
-        input.setSecureValidation(context.secureValidation);
-        return input;
+    public XMLSignatureInput engineResolveURI(ResourceResolverContext context) throws ResourceResolverException {
+        try {
+            XMLSignatureInput input = new XMLSignatureInput(Files.newInputStream(resourcePath));
+            input.setSecureValidation(context.secureValidation);
+            return input;
+        } catch (IOException e) {
+            throw new ResourceResolverException(e, context.uriToResolve, context.baseUri, "generic.EmptyMessage");
+        }
     }
 
     /**
@@ -72,8 +70,4 @@
         return context.uriToResolve == null;
     }
 
-    /** {@inheritDoc} */
-    public String[] engineGetPropertyKeys() {
-        return new String[0];
-    }
 }
diff --git a/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverDirectHTTP.java b/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverDirectHTTP.java
index 6bdc29f..7f99757 100644
--- a/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverDirectHTTP.java
+++ b/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverDirectHTTP.java
@@ -29,6 +29,8 @@
 import java.net.URL;
 import java.net.URLConnection;
 import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Map;
 
 import org.apache.xml.security.signature.XMLSignatureInput;
 import org.apache.xml.security.utils.XMLUtils;
@@ -86,9 +88,15 @@
     /** Field HttpProxyPass */
     private static final int HttpBasicPass = 5;
 
-    @Override
-    public boolean engineIsThreadSafe() {
-        return true;
+    private final Map<String, String> resolverProperties;
+
+    public ResolverDirectHTTP() {
+        resolverProperties = Collections.emptyMap();
+    }
+
+    public ResolverDirectHTTP(Map<String, String> resolverProperties) {
+        this.resolverProperties =
+            Collections.unmodifiableMap(resolverProperties != null ? resolverProperties : Collections.emptyMap());
     }
 
     /**
@@ -102,7 +110,7 @@
             // calculate new URI
             URI uriNew = getNewURI(context.uriToResolve, context.baseUri);
             URL url = uriNew.toURL();
-            URLConnection urlConnection = openConnection(url);
+            URLConnection urlConnection = openConnection(url, context);
 
             // check if Basic authentication is required
             String auth = urlConnection.getHeaderField("WWW-Authenticate");
@@ -110,12 +118,12 @@
             if (auth != null && auth.startsWith("Basic")) {
                 // do http basic authentication
                 String user =
-                    engineGetProperty(ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpBasicUser]);
+                    getProperty(context, ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpBasicUser]);
                 String pass =
-                    engineGetProperty(ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpBasicPass]);
+                    getProperty(context, ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpBasicPass]);
 
                 if (user != null && pass != null) {
-                    urlConnection = openConnection(url);
+                    urlConnection = openConnection(url, context);
 
                     String password = user + ":" + pass;
                     String encodedPassword = XMLUtils.encodeToString(password.getBytes(StandardCharsets.ISO_8859_1));
@@ -160,16 +168,16 @@
         }
     }
 
-    private URLConnection openConnection(URL url) throws IOException {
+    private URLConnection openConnection(URL url, ResourceResolverContext context) throws IOException {
 
         String proxyHostProp =
-                engineGetProperty(ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpProxyHost]);
+            getProperty(context, ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpProxyHost]);
         String proxyPortProp =
-                engineGetProperty(ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpProxyPort]);
+            getProperty(context, ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpProxyPort]);
         String proxyUser =
-                engineGetProperty(ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpProxyUser]);
+            getProperty(context, ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpProxyUser]);
         String proxyPass =
-                engineGetProperty(ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpProxyPass]);
+            getProperty(context, ResolverDirectHTTP.properties[ResolverDirectHTTP.HttpProxyPass]);
 
         Proxy proxy = null;
         if (proxyHostProp != null && proxyPortProp != null) {
@@ -248,4 +256,14 @@
         return newUri;
     }
 
+    private String getProperty(ResourceResolverContext context, String propertyName) {
+        // First check the properties defined on this Resolver.
+        if (resolverProperties.containsKey(propertyName)) {
+            return resolverProperties.get(propertyName);
+        }
+
+        // Otherwise defer to the passed in properties
+        return context.getProperties().get(propertyName);
+    }
+
 }
diff --git a/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverFragment.java b/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverFragment.java
index 1c26e5b..b6804c1 100644
--- a/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverFragment.java
+++ b/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverFragment.java
@@ -39,11 +39,6 @@
     private static final org.slf4j.Logger LOG =
         org.slf4j.LoggerFactory.getLogger(ResolverFragment.class);
 
-    @Override
-    public boolean engineIsThreadSafe() {
-        return true;
-    }
-
     /**
      * {@inheritDoc}
      */
diff --git a/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverLocalFilesystem.java b/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverLocalFilesystem.java
index fc03ec5..f35aef8 100644
--- a/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverLocalFilesystem.java
+++ b/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverLocalFilesystem.java
@@ -39,11 +39,6 @@
     private static final org.slf4j.Logger LOG =
         org.slf4j.LoggerFactory.getLogger(ResolverLocalFilesystem.class);
 
-    @Override
-    public boolean engineIsThreadSafe() {
-        return true;
-    }
-
     /**
      * {@inheritDoc}
      */
diff --git a/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverXPointer.java b/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverXPointer.java
index eae8d1b..4c587c4 100644
--- a/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverXPointer.java
+++ b/src/main/java/org/apache/xml/security/utils/resolver/implementations/ResolverXPointer.java
@@ -49,11 +49,6 @@
     private static final String XP = "#xpointer(id(";
     private static final int XP_LENGTH = XP.length();
 
-    @Override
-    public boolean engineIsThreadSafe() {
-        return true;
-    }
-
     /**
      * {@inheritDoc}
      */
diff --git a/src/test/java/org/apache/xml/security/test/dom/utils/resolver/ResolverDirectHTTPTest.java b/src/test/java/org/apache/xml/security/test/dom/utils/resolver/ResolverDirectHTTPTest.java
index d1a8d3b..ad0e207 100644
--- a/src/test/java/org/apache/xml/security/test/dom/utils/resolver/ResolverDirectHTTPTest.java
+++ b/src/test/java/org/apache/xml/security/test/dom/utils/resolver/ResolverDirectHTTPTest.java
@@ -20,7 +20,6 @@
 
 import org.apache.xml.security.Init;
 import org.apache.xml.security.test.dom.TestUtils;
-import org.apache.xml.security.utils.resolver.ResourceResolver;
 import org.apache.xml.security.utils.resolver.ResourceResolverContext;
 import org.apache.xml.security.utils.resolver.ResourceResolverException;
 import org.apache.xml.security.utils.resolver.implementations.ResolverDirectHTTP;
@@ -33,6 +32,9 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.fail;
 
+import java.util.HashMap;
+import java.util.Map;
+
 
 public class ResolverDirectHTTPTest {
 
@@ -51,20 +53,6 @@
     }
 
     @Test
-    public void testBug40783() throws Exception {
-        Document doc = TestUtils.newDocument();
-        Attr uri = doc.createAttribute("id");
-        uri.setNodeValue("urn:ddd:uuu");
-        doc.createElement("test").setAttributeNode(uri);
-        try {
-            ResourceResolver resolver = ResourceResolver.getInstance(uri, null, true);
-            fail("No exception thrown, but resolver found: " + resolver);
-        } catch (ResourceResolverException e) {
-            //
-        }
-    }
-
-    @Test
     @Disabled
     public void testProxyAuth() throws Exception {
         Document doc = TestUtils.newDocument();
@@ -72,12 +60,13 @@
         uri.setNodeValue(url);
 
         ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-        resolverDirectHTTP.engineSetProperty("http.proxy.host",proxyHost);
-        resolverDirectHTTP.engineSetProperty("http.proxy.port", proxyPort);
-        resolverDirectHTTP.engineSetProperty("http.proxy.username", proxyUsername);
-        resolverDirectHTTP.engineSetProperty("http.proxy.password", proxyPassword);
+        Map<String, String> resolverProperties = new HashMap<>();
+        resolverProperties.put("http.proxy.host",proxyHost);
+        resolverProperties.put("http.proxy.port", proxyPort);
+        resolverProperties.put("http.proxy.username", proxyUsername);
+        resolverProperties.put("http.proxy.password", proxyPassword);
         ResourceResolverContext context =
-            new ResourceResolverContext(uri, url, true);
+            new ResourceResolverContext(uri, url, true, resolverProperties);
         resolverDirectHTTP.engineResolveURI(context);
     }
 
@@ -89,12 +78,13 @@
         uri.setNodeValue(url);
 
         ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-        resolverDirectHTTP.engineSetProperty("http.proxy.host",proxyHost);
-        resolverDirectHTTP.engineSetProperty("http.proxy.port", proxyPort);
-        resolverDirectHTTP.engineSetProperty("http.proxy.username", proxyUsername);
-        resolverDirectHTTP.engineSetProperty("http.proxy.password", "wrongPassword");
+        Map<String, String> resolverProperties = new HashMap<>();
+        resolverProperties.put("http.proxy.host",proxyHost);
+        resolverProperties.put("http.proxy.port", proxyPort);
+        resolverProperties.put("http.proxy.username", proxyUsername);
+        resolverProperties.put("http.proxy.password", "wrongPassword");
         ResourceResolverContext context =
-            new ResourceResolverContext(uri, url, true);
+            new ResourceResolverContext(uri, url, true, resolverProperties);
         try {
             resolverDirectHTTP.engineResolveURI(context);
             fail("Expected ResourceResolverException");
@@ -111,10 +101,11 @@
         uri.setNodeValue(url);
 
         ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-        resolverDirectHTTP.engineSetProperty("http.basic.username", serverUsername);
-        resolverDirectHTTP.engineSetProperty("http.basic.password", serverPassword);
+        Map<String, String> resolverProperties = new HashMap<>();
+        resolverProperties.put("http.basic.username", serverUsername);
+        resolverProperties.put("http.basic.password", serverPassword);
         ResourceResolverContext context =
-            new ResourceResolverContext(uri, url, true);
+            new ResourceResolverContext(uri, url, true, resolverProperties);
         resolverDirectHTTP.engineResolveURI(context);
     }
 
@@ -126,10 +117,11 @@
         uri.setNodeValue(url);
 
         ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-        resolverDirectHTTP.engineSetProperty("http.basic.username", serverUsername);
-        resolverDirectHTTP.engineSetProperty("http.basic.password", "wrongPassword");
+        Map<String, String> resolverProperties = new HashMap<>();
+        resolverProperties.put("http.basic.username", serverUsername);
+        resolverProperties.put("http.basic.password", "wrongPassword");
         ResourceResolverContext context =
-            new ResourceResolverContext(uri, url, true);
+            new ResourceResolverContext(uri, url, true, resolverProperties);
         try {
             resolverDirectHTTP.engineResolveURI(context);
             fail("Expected ResourceResolverException");
@@ -146,14 +138,15 @@
         uri.setNodeValue(url);
 
         ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-        resolverDirectHTTP.engineSetProperty("http.proxy.host",proxyHost);
-        resolverDirectHTTP.engineSetProperty("http.proxy.port", proxyPort);
-        resolverDirectHTTP.engineSetProperty("http.proxy.username", proxyUsername);
-        resolverDirectHTTP.engineSetProperty("http.proxy.password", proxyPassword);
-        resolverDirectHTTP.engineSetProperty("http.basic.username", serverUsername);
-        resolverDirectHTTP.engineSetProperty("http.basic.password", serverPassword);
+        Map<String, String> resolverProperties = new HashMap<>();
+        resolverProperties.put("http.proxy.host",proxyHost);
+        resolverProperties.put("http.proxy.port", proxyPort);
+        resolverProperties.put("http.proxy.username", proxyUsername);
+        resolverProperties.put("http.proxy.password", proxyPassword);
+        resolverProperties.put("http.basic.username", serverUsername);
+        resolverProperties.put("http.basic.password", serverPassword);
         ResourceResolverContext context =
-            new ResourceResolverContext(uri, url, true);
+            new ResourceResolverContext(uri, url, true, resolverProperties);
         resolverDirectHTTP.engineResolveURI(context);
     }
 }
diff --git a/src/test/java/org/apache/xml/security/test/dom/utils/resolver/ResourceResolverTest.java b/src/test/java/org/apache/xml/security/test/dom/utils/resolver/ResourceResolverTest.java
index d12281e..975c540 100644
--- a/src/test/java/org/apache/xml/security/test/dom/utils/resolver/ResourceResolverTest.java
+++ b/src/test/java/org/apache/xml/security/test/dom/utils/resolver/ResourceResolverTest.java
@@ -23,9 +23,11 @@
 
 import org.apache.xml.security.test.dom.TestUtils;
 import org.apache.xml.security.utils.resolver.ResourceResolver;
+import org.apache.xml.security.utils.resolver.ResourceResolverContext;
 import org.w3c.dom.Attr;
 import org.w3c.dom.Document;
 
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.fail;
 
 /**
@@ -53,18 +55,21 @@
         Document doc = TestUtils.newDocument();
         Attr uriAttr = doc.createAttribute("URI");
         uriAttr.setValue("http://www.apache.org");
-        ResourceResolver res =
-            ResourceResolver.getInstance(uriAttr, "http://www.apache.org", true);
+
+        ResourceResolverContext resolverContext =
+            new ResourceResolverContext(uriAttr, "http://www.apache.org", true);
         try {
             uriAttr.setValue("http://xmldsig.pothole.com/xml-stylesheet.txt");
-            res.resolve(uriAttr, null, true);
+            resolverContext = new ResourceResolverContext(uriAttr, null, true);
+            assertNotNull(ResourceResolver.resolve(resolverContext));
         } catch (Exception e) {
             fail(uriAttr.getValue()
                 + " should be resolvable by the OfflineResolver");
         }
         try {
             uriAttr.setValue("http://www.apache.org");
-            res.resolve(uriAttr, null, true);
+            resolverContext = new ResourceResolverContext(uriAttr, null, true);
+            ResourceResolver.resolve(resolverContext);
             fail(uriAttr.getValue() + " should not be resolvable by the OfflineResolver");
         } catch (Exception e) {
             //
@@ -78,9 +83,12 @@
         String basedir = System.getProperty("basedir");
         String file = new File(basedir, "pom.xml").toURI().toString();
         uriAttr.setValue(file);
-        ResourceResolver res = ResourceResolver.getInstance(uriAttr, file, false);
+
+        ResourceResolverContext resolverContext =
+            new ResourceResolverContext(uriAttr, file, false);
         try {
-            res.resolve(uriAttr, "", true);
+            resolverContext = new ResourceResolverContext(uriAttr, "", false);
+            assertNotNull(ResourceResolver.resolve(resolverContext));
         } catch (Exception e) {
             fail(e.getMessage());
         }
diff --git a/src/test/java/org/apache/xml/security/test/stax/signature/BaltimoreTest.java b/src/test/java/org/apache/xml/security/test/stax/signature/BaltimoreTest.java
index db9e099..fe291da 100644
--- a/src/test/java/org/apache/xml/security/test/stax/signature/BaltimoreTest.java
+++ b/src/test/java/org/apache/xml/security/test/stax/signature/BaltimoreTest.java
@@ -22,7 +22,6 @@
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
 import java.math.BigInteger;
-import java.net.InetSocketAddress;
 import java.net.Proxy;
 import java.nio.charset.StandardCharsets;
 import java.security.Key;
@@ -65,7 +64,6 @@
 import org.apache.xml.security.test.stax.utils.TestUtils;
 import org.apache.xml.security.test.stax.utils.XMLSecEventAllocator;
 import org.apache.xml.security.utils.XMLUtils;
-import org.apache.xml.security.utils.resolver.implementations.ResolverDirectHTTP;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.w3c.dom.Document;
@@ -346,10 +344,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -401,10 +395,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -679,10 +669,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -734,10 +720,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -789,10 +771,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -849,10 +827,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -903,10 +877,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -948,10 +918,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -993,10 +959,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -1053,10 +1015,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -1107,10 +1065,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -1194,10 +1148,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -1254,10 +1204,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -1308,10 +1254,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -1353,10 +1295,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -1398,10 +1336,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -1458,10 +1392,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -1512,10 +1442,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
diff --git a/src/test/java/org/apache/xml/security/test/stax/signature/PhaosTest.java b/src/test/java/org/apache/xml/security/test/stax/signature/PhaosTest.java
index cc0fa43..83264ad 100644
--- a/src/test/java/org/apache/xml/security/test/stax/signature/PhaosTest.java
+++ b/src/test/java/org/apache/xml/security/test/stax/signature/PhaosTest.java
@@ -29,7 +29,6 @@
 import org.apache.xml.security.test.stax.utils.TestUtils;
 import org.apache.xml.security.test.stax.utils.XMLSecEventAllocator;
 import org.apache.xml.security.utils.XMLUtils;
-import org.apache.xml.security.utils.resolver.implementations.ResolverDirectHTTP;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.w3c.dom.Document;
@@ -46,7 +45,6 @@
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
-import java.net.InetSocketAddress;
 import java.net.Proxy;
 import java.nio.charset.StandardCharsets;
 
@@ -84,10 +82,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -192,10 +186,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
@@ -320,10 +310,6 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress) proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress) proxy.address()).getPort());
-
             TestUtils.switchAllowNotSameDocumentReferences(true);
 
             // Read in plaintext document
diff --git a/src/test/java/org/apache/xml/security/test/stax/signature/SignatureCreationReferenceURIResolverTest.java b/src/test/java/org/apache/xml/security/test/stax/signature/SignatureCreationReferenceURIResolverTest.java
index 3d6177a..ef8f3ce 100644
--- a/src/test/java/org/apache/xml/security/test/stax/signature/SignatureCreationReferenceURIResolverTest.java
+++ b/src/test/java/org/apache/xml/security/test/stax/signature/SignatureCreationReferenceURIResolverTest.java
@@ -29,7 +29,9 @@
 import java.security.KeyStore;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import javax.xml.namespace.QName;
 import javax.xml.stream.XMLStreamReader;
@@ -168,9 +170,10 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress)proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress)proxy.address()).getPort());
+            Map<String, String> resolverProperties = new HashMap<>();
+            resolverProperties.put("http.proxy.host", ((InetSocketAddress)proxy.address()).getAddress().getHostAddress());
+            resolverProperties.put("http.proxy.port", "" + ((InetSocketAddress)proxy.address()).getPort());
+            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP(resolverProperties);
 
             // Set up the Configuration
             XMLSecurityProperties properties = new XMLSecurityProperties();
diff --git a/src/test/java/org/apache/xml/security/test/stax/signature/SignatureVerificationReferenceURIResolverTest.java b/src/test/java/org/apache/xml/security/test/stax/signature/SignatureVerificationReferenceURIResolverTest.java
index 708db24..245209d 100644
--- a/src/test/java/org/apache/xml/security/test/stax/signature/SignatureVerificationReferenceURIResolverTest.java
+++ b/src/test/java/org/apache/xml/security/test/stax/signature/SignatureVerificationReferenceURIResolverTest.java
@@ -28,7 +28,9 @@
 import java.security.KeyStore;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.UUID;
 
 import javax.xml.stream.XMLStreamReader;
@@ -204,9 +206,10 @@
         try {
             ResolverHttp.setProxy(proxy);
 
-            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP();
-            resolverDirectHTTP.engineSetProperty("http.proxy.host", ((InetSocketAddress)proxy.address()).getAddress().getHostAddress());
-            resolverDirectHTTP.engineSetProperty("http.proxy.port", "" + ((InetSocketAddress)proxy.address()).getPort());
+            Map<String, String> resolverProperties = new HashMap<>();
+            resolverProperties.put("http.proxy.host", ((InetSocketAddress)proxy.address()).getAddress().getHostAddress());
+            resolverProperties.put("http.proxy.port", "" + ((InetSocketAddress)proxy.address()).getPort());
+            ResolverDirectHTTP resolverDirectHTTP = new ResolverDirectHTTP(resolverProperties);
 
             TestUtils.switchAllowNotSameDocumentReferences(true);