package com.helger.schematron.config;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathFactoryConfigurationException;
import javax.xml.xpath.XPathFunctionResolver;
import javax.xml.xpath.XPathVariableResolver;
import java.lang.reflect.InvocationTargetException;

public class XPathConfigBuilder {

    private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];

    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];

    private Class<? extends XPathFactory> xPathFactoryClass;

    private XPathVariableResolver xPathVariableResolver;

    private XPathFunctionResolver xPathFunctionResolver;

    public XPathConfigBuilder() {
    }

    public Class<? extends XPathFactory> getxPathFactoryClass() {
        return xPathFactoryClass;
    }

    public XPathVariableResolver getxPathVariableResolver() {
        return xPathVariableResolver;
    }

    public XPathFunctionResolver getxPathFunctionResolver() {
        return xPathFunctionResolver;
    }

    public XPathConfigBuilder setXPathFactoryClass(@Nonnull Class<? extends XPathFactory> xPathFactoryClass) {
        this.xPathFactoryClass = xPathFactoryClass;
        return this;
    }

    public XPathConfigBuilder setXPathVariableResolver(@Nullable XPathVariableResolver xPathVariableResolver) {
        this.xPathVariableResolver = xPathVariableResolver;
        return this;
    }

    public XPathConfigBuilder setXPathFunctionResolver(@Nullable XPathFunctionResolver xPathFunctionResolver) {
        this.xPathFunctionResolver = xPathFunctionResolver;
        return this;
    }

    public XPathConfig build() throws XPathFactoryConfigurationException {
        XPathFactory aXPathFactory = null;
        if (xPathFactoryClass != null) {
            try {
                aXPathFactory = xPathFactoryClass.getConstructor(EMPTY_CLASS_ARRAY)
                        .newInstance(EMPTY_OBJECT_ARRAY);
            } catch (InstantiationException e) {
                throw new XPathFactoryConfigurationException(e);
            } catch (IllegalAccessException e) {
                throw new XPathFactoryConfigurationException(e);
            } catch (InvocationTargetException e) {
                throw new XPathFactoryConfigurationException(e.getCause());
            } catch (NoSuchMethodException e) {
                throw new XPathFactoryConfigurationException(e);
            }
        } else {
            // DEFAULT as fallback
            aXPathFactory = XPathConfigs.SAXON_FIRST;
        }
        XPathConfig result = new XPathConfigImpl(aXPathFactory, xPathVariableResolver, xPathFunctionResolver);
        return result;
    }
}

@@ -582,16 +582,56 @@
 Class;%0A%0A
+    private String globalXPathFactory;%0A%0A
     priv
@@ -675,24 +675,24 @@
 leResolver;%0A
-
 %0A    private
@@ -878,32 +878,118 @@
 ryClass;%0A    %7D%0A%0A
+    public String getGlobalXPathFactory() %7B%0A        return globalXPathFactory;%0A    %7D%0A%0A
     public XPath
@@ -1369,32 +1369,863 @@
 rn this;%0A    %7D%0A%0A
+    /**%0A     * With Java 11+ module path system, you can't access%0A     * @link%7Bcom.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl%7D as%0A     * 'package com.sun.org.apache.xpath.internal.jaxp is declared in module java.xml, which does not export it'.%0A     * %3Cp%3E%0A     * The only way to use it, is to set/alter the 'javax.xml.xpath.XPathFactory' system property. However, this change is%0A     * %3Cemph%3Eglobal%3C/emph%3E to the application.%0A     * %3C/p%3E%0A     *%0A     * @param globalXPathFactory%0A     *        Fully qualified class name of the 'default' %7B@link XPathFactory%7D. Most commonly set to%0A     *        'com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl'.%0A     */%0A    public XPathConfigBuilder setGlobalXPathFactory(String globalXPathFactory) %7B%0A        this.globalXPathFactory = globalXPathFactory;%0A        return this;%0A    %7D%0A%0A
     public XPath
@@ -2683,16 +2683,152 @@
 ption %7B%0A
+        if (globalXPathFactory != null) %7B%0A            System.setProperty(%22javax.xml.xpath.XPathFactory%22, globalXPathFactory);%0A        %7D%0A
         
@@ -3524,32 +3524,32 @@
 onException(e);%0A
-
             %7D%0A  
@@ -3538,32 +3538,137 @@
 ;%0A            %7D%0A
+        %7D else if (globalXPathFactory != null) %7B%0A            aXPathFactory = XPathFactory.newInstance();%0A
         %7D else %7B

introduce setGlobalXPathFactory