You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by jl...@apache.org on 2022/11/17 22:40:58 UTC

[tomee] branch main updated: Restore all CXF files and do some tweaks for now

This is an automated email from the ASF dual-hosted git repository.

jlmonteiro pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomee.git


The following commit(s) were added to refs/heads/main by this push:
     new 48d51f7b7f Restore all CXF files and do some tweaks for now
48d51f7b7f is described below

commit 48d51f7b7f7f6baa017da66d540554c3240b2ea2
Author: Jean-Louis Monteiro <jl...@tomitribe.com>
AuthorDate: Thu Nov 17 23:40:48 2022 +0100

    Restore all CXF files and do some tweaks for now
---
 .../java/org/apache/cxf/annotations/Policy.java    |   80 +
 .../apache/cxf/annotations/WSDLDocumentation.java  |   88 +
 .../cxf/attachment/AttachmentDataSource.java       |  107 +
 .../cxf/attachment/AttachmentDeserializer.java     |  462 ++++
 .../cxf/attachment/AttachmentSerializer.java       |  345 +++
 .../org/apache/cxf/attachment/AttachmentUtil.java  |  572 +++++
 .../apache/cxf/attachment/Base64DecoderStream.java |  196 ++
 .../apache/cxf/attachment/ContentDisposition.java  |  144 ++
 .../cxf/attachment/LazyAttachmentCollection.java   |  362 ++++
 .../cxf/attachment/MimeBodyPartInputStream.java    |  275 +++
 .../java/org/apache/cxf/bus/CXFBusFactory.java     |   47 +
 .../bus/blueprint/BundleDelegatingClassLoader.java |  134 ++
 .../cxf/bus/blueprint/BusDefinitionParser.java     |   72 +
 .../apache/cxf/bus/blueprint/ConfigurerImpl.java   |  180 ++
 .../org/apache/cxf/bus/extension/Extension.java    |  291 +++
 .../cxf/bus/extension/ExtensionManagerImpl.java    |  381 ++++
 .../ServiceContractResolverRegistryImpl.java       |  113 +
 .../java/org/apache/cxf/bus/osgi/CXFActivator.java |  134 ++
 .../cxf/bus/osgi/CXFExtensionBundleListener.java   |  181 ++
 .../org/apache/cxf/bus/osgi/OSGIBusListener.java   |  224 ++
 .../cxf/bus/resource/ResourceManagerImpl.java      |   85 +
 .../apache/cxf/bus/spring/BusDefinitionParser.java |  310 +++
 .../apache/cxf/bus/spring/BusEntityResolver.java   |   94 +
 .../cxf/bus/spring/BusExtensionPostProcessor.java  |   71 +
 .../cxf/bus/spring/Jsr250BeanPostProcessor.java    |  164 ++
 .../apache/cxf/bus/spring/NamespaceHandler.java    |   57 +
 .../java/org/apache/cxf/bus/spring/SpringBus.java  |  142 ++
 .../cxf/catalog/CatalogXmlSchemaURIResolver.java   |  102 +
 .../jsse/MultiKeyPasswordKeyManager.java           |   84 +
 .../configuration/jsse/TLSClientParameters.java    |  258 +++
 .../configuration/jsse/TLSParameterJaxBUtils.java  |  420 ++++
 .../cxf/configuration/spring/ConfigurerImpl.java   |  288 +++
 .../cxf/databinding/source/SourceDataBinding.java  |  104 +
 .../cxf/databinding/stax/StaxDataBinding.java      |  187 ++
 .../cxf/endpoint/AbstractConduitSelector.java      |  308 +++
 .../org/apache/cxf/endpoint/ClientCallback.java    |  166 ++
 .../java/org/apache/cxf/endpoint/ClientImpl.java   | 1192 +++++++++++
 .../java/org/apache/cxf/endpoint/EndpointImpl.java |  220 ++
 .../java/org/apache/cxf/endpoint/ServerImpl.java   |  221 ++
 .../org/apache/cxf/feature/FastInfosetFeature.java |  110 +
 .../org/apache/cxf/feature/WrappedFeature.java     |   61 +
 .../cxf/feature/transform/XSLTOutInterceptor.java  |  210 ++
 .../patch/java/org/apache/cxf/headers/Header.java  |   78 +
 .../java/org/apache/cxf/helpers/DOMUtils.java      |  895 ++++++++
 .../patch/java/org/apache/cxf/helpers/IOUtils.java |  428 ++++
 .../java/org/apache/cxf/helpers/ServiceUtils.java  |  214 ++
 .../AbstractFaultChainInitiatorObserver.java       |  142 ++
 .../interceptor/AbstractLoggingInterceptor.java    |  298 +++
 .../cxf/interceptor/AnnotationInterceptors.java    |  151 ++
 .../cxf/interceptor/AttachmentInInterceptor.java   |   72 +
 .../cxf/interceptor/ClientOutFaultObserver.java    |   68 +
 .../interceptor/InFaultChainInitiatorObserver.java |   84 +
 .../apache/cxf/interceptor/InterceptorChain.java   |  109 +
 .../org/apache/cxf/interceptor/LoggingMessage.java |  133 ++
 .../interceptor/OneWayProcessorInterceptor.java    |  177 ++
 .../OutFaultChainInitiatorObserver.java            |   84 +
 .../security/DefaultSecurityContext.java           |  188 ++
 .../interceptor/security/JAASLoginInterceptor.java |  233 ++
 .../cxf/internal/CXFAPINamespaceHandler.java       |  127 ++
 .../apache/cxf/io/CacheAndWriteOutputStream.java   |   96 +
 .../patch/java/org/apache/cxf/io/CachedWriter.java |  665 ++++++
 .../java/org/apache/cxf/io/ReaderInputStream.java  |  294 +++
 .../apache/cxf/io/WriteOnCloseOutputStream.java    |   46 +
 .../apache/cxf/jaxrs/provider/ProviderFactory.java |  132 +-
 .../java/org/apache/cxf/message/MessageUtils.java  |  302 +++
 .../java/org/apache/cxf/phase/PhaseChainCache.java |  137 ++
 .../apache/cxf/phase/PhaseInterceptorChain.java    |  857 ++++++++
 .../cxf/service/factory/FactoryBeanListener.java   |  145 ++
 .../apache/cxf/service/invoker/FactoryInvoker.java |   70 +
 .../service/model/AbstractPropertiesHolder.java    |  271 +++
 .../org/apache/cxf/service/model/FaultInfo.java    |   61 +
 .../apache/cxf/service/model/InterfaceInfo.java    |  124 ++
 .../apache/cxf/service/model/OperationInfo.java    |  242 +++
 .../cxf/service/model/UnwrappedOperationInfo.java  |   72 +
 .../java/org/apache/cxf/staxutils/StaxUtils.java   | 2222 ++++++++++++++++++++
 .../apache/cxf/staxutils/W3CDOMStreamReader.java   |  429 ++++
 pom.xml                                            |    2 +-
 77 files changed, 18809 insertions(+), 81 deletions(-)

diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/annotations/Policy.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/annotations/Policy.java
new file mode 100644
index 0000000000..a0d4a75ea8
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/annotations/Policy.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Attaches a Policy to a service or method
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@Inherited
+public @interface Policy {
+
+    String uri();
+
+    boolean includeInWSDL() default true;
+
+
+    /**
+     * The place to put the PolicyReference.  The Default depends on the
+     * location of the annotation.   On the method in the SEI, it would be
+     * the binding/operation, on the SEI, it would be the binding, on the
+     * service impl, the service element.
+     * @return location
+     */
+    Placement placement() default Placement.DEFAULT;
+
+    /**
+     * If Placement is PORT_TYPE_OPERATION_FAULT, or BINDING_OPERATION_FAULT,
+     * return the fault class associated with this documentation
+     * @return the fault class
+     */
+    Class<?> faultClass() default DEFAULT.class;
+
+    enum Placement {
+        DEFAULT,
+
+        PORT_TYPE,
+        PORT_TYPE_OPERATION,
+        PORT_TYPE_OPERATION_INPUT,
+        PORT_TYPE_OPERATION_OUTPUT,
+        PORT_TYPE_OPERATION_FAULT,
+
+        BINDING,
+        BINDING_OPERATION,
+        BINDING_OPERATION_INPUT,
+        BINDING_OPERATION_OUTPUT,
+        BINDING_OPERATION_FAULT,
+
+        SERVICE,
+        SERVICE_PORT,
+    }
+
+    final class DEFAULT { }
+}
+
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/annotations/WSDLDocumentation.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/annotations/WSDLDocumentation.java
new file mode 100644
index 0000000000..9116f1c566
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/annotations/WSDLDocumentation.java
@@ -0,0 +1,88 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.annotations;
+
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Adds documentation nodes to the generated WSDL
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@Inherited
+public @interface WSDLDocumentation {
+    /**
+     * The documentation to add
+     * @return documentation string
+     */
+    String value();
+
+    /**
+     * The place to put the documentation.  The Default depends on the
+     * location of the annotation.   On the method in the SEI, it would be
+     * the portType/operation, on the SEI, it would be the portType, on the
+     * service impl, the service element.
+     * @return location
+     */
+    Placement placement() default Placement.DEFAULT;
+
+    /**
+     * If Placement is FAULT_MESSAGE, PORT_FAULT, or BINDING_FAULT,
+     * return the fault class associated with this documentation
+     * @return the fault class
+     */
+    Class<?> faultClass() default DEFAULT.class;
+
+    enum Placement {
+        DEFAULT,
+        TOP,
+
+        INPUT_MESSAGE,
+        OUTPUT_MESSAGE,
+        FAULT_MESSAGE,
+
+        PORT_TYPE,
+        PORT_TYPE_OPERATION,
+        PORT_TYPE_OPERATION_INPUT,
+        PORT_TYPE_OPERATION_OUTPUT,
+        PORT_TYPE_OPERATION_FAULT,
+
+        BINDING,
+        BINDING_OPERATION,
+        BINDING_OPERATION_INPUT,
+        BINDING_OPERATION_OUTPUT,
+        BINDING_OPERATION_FAULT,
+
+        SERVICE,
+        SERVICE_PORT,
+
+    }
+
+
+    final class DEFAULT { }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/AttachmentDataSource.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/AttachmentDataSource.java
new file mode 100644
index 0000000000..d443832732
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/AttachmentDataSource.java
@@ -0,0 +1,107 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.attachment;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import jakarta.activation.DataSource;
+
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.io.CacheSizeExceededException;
+import org.apache.cxf.io.CachedOutputStream;
+import org.apache.cxf.message.Message;
+
+public class AttachmentDataSource implements DataSource {
+
+    private final String ct;
+    private CachedOutputStream cache;
+    private InputStream ins;
+    private DelegatingInputStream delegate;
+    private String name;
+
+    public AttachmentDataSource(String ctParam, InputStream inParam) {
+        this.ct = ctParam;
+        ins = inParam;
+    }
+
+    public boolean isCached() {
+        return cache != null;
+    }
+    public void cache(Message message) throws IOException {
+        if (cache == null) {
+            cache = new CachedOutputStream();
+            AttachmentUtil.setStreamedAttachmentProperties(message, cache);
+            try {
+                IOUtils.copyAndCloseInput(ins, cache);
+                cache.lockOutputStream();
+                if (delegate != null) {
+                    delegate.setInputStream(cache.getInputStream());
+                }
+            } catch (CacheSizeExceededException | IOException cee) {
+                cache.close();
+                cache = null;
+                throw cee;
+            } finally {
+                ins = null;
+            }
+        }
+    }
+    public void hold(Message message) throws IOException {
+        cache(message);
+        cache.holdTempFile();
+    }
+    public void release() {
+        if (cache != null) {
+            cache.releaseTempFileHold();
+        }
+    }
+
+    public String getContentType() {
+        return ct;
+    }
+
+    public InputStream getInputStream() {
+        try {
+            if (cache != null) {
+                return cache.getInputStream();
+            }
+            if (delegate == null) {
+                delegate = new DelegatingInputStream(ins);
+            }
+            return delegate;
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public OutputStream getOutputStream() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/AttachmentDeserializer.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/AttachmentDeserializer.java
new file mode 100644
index 0000000000..4bd6b27d61
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/AttachmentDeserializer.java
@@ -0,0 +1,462 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.attachment;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import jakarta.activation.DataSource;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.common.util.SystemPropertyAction;
+import org.apache.cxf.helpers.HttpHeaderHelper;
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.io.CachedOutputStream;
+import org.apache.cxf.message.Attachment;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageUtils;
+
+public class AttachmentDeserializer {
+    public static final String ATTACHMENT_PART_HEADERS = AttachmentDeserializer.class.getName() + ".headers";
+
+    /**
+     * Allowed value is any instance of {@link File} or {@link String}.
+     */
+    public static final String ATTACHMENT_DIRECTORY = "attachment-directory";
+
+    /**
+     * The memory threshold of attachments. Allowed value is any instance of {@link Number} or {@link String}.
+     * The default is {@link AttachmentDeserializer#THRESHOLD}.
+     */
+    public static final String ATTACHMENT_MEMORY_THRESHOLD = "attachment-memory-threshold";
+
+    /**
+     * The maximum size of the attachment. Allowed value is any of {@link Number} or {@link String}.
+     */
+    public static final String ATTACHMENT_MAX_SIZE = "attachment-max-size";
+
+    /**
+     * The maximum number of attachments permitted in a message. The default is 50.
+     */
+    public static final String ATTACHMENT_MAX_COUNT = "attachment-max-count";
+
+    /**
+     * The maximum MIME Header Length. The default is 300.
+     */
+    public static final String ATTACHMENT_MAX_HEADER_SIZE = "attachment-max-header-size";
+    public static final int DEFAULT_MAX_HEADER_SIZE =
+        SystemPropertyAction.getInteger("org.apache.cxf.attachment-max-header-size", 300);
+
+    public static final int THRESHOLD = 1024 * 100; //100K (byte unit)
+
+    private static final Pattern CONTENT_TYPE_BOUNDARY_PATTERN = Pattern.compile("boundary=\"?([^\";]*)");
+
+    private static final Pattern INPUT_STREAM_BOUNDARY_PATTERN =
+            Pattern.compile("^--(\\S*)$", Pattern.MULTILINE);
+
+    private static final Logger LOG = LogUtils.getL7dLogger(AttachmentDeserializer.class);
+
+    private static final int PUSHBACK_AMOUNT = 2048;
+
+    private boolean lazyLoading = true;
+
+    private PushbackInputStream stream;
+    private int createCount;
+    private int closedCount;
+    private boolean closed;
+
+    private byte[] boundary;
+
+    private LazyAttachmentCollection attachments;
+
+    private Message message;
+
+    private InputStream body;
+
+    private Set<DelegatingInputStream> loaded = new HashSet<>();
+    private List<String> supportedTypes;
+
+    private int maxHeaderLength = DEFAULT_MAX_HEADER_SIZE;
+
+    public AttachmentDeserializer(Message message) {
+        this(message, Collections.singletonList("multipart/related"));
+    }
+
+    public AttachmentDeserializer(Message message, List<String> supportedTypes) {
+        this.message = message;
+        this.supportedTypes = supportedTypes;
+
+        // Get the maximum Header length from configuration
+        maxHeaderLength = MessageUtils.getContextualInteger(message, ATTACHMENT_MAX_HEADER_SIZE,
+                                                            DEFAULT_MAX_HEADER_SIZE);
+    }
+
+    public void initializeAttachments() throws IOException {
+        initializeRootMessage();
+
+        Object maxCountProperty = message.getContextualProperty(AttachmentDeserializer.ATTACHMENT_MAX_COUNT);
+        int maxCount = 50;
+        if (maxCountProperty != null) {
+            if (maxCountProperty instanceof Integer) {
+                maxCount = (Integer)maxCountProperty;
+            } else {
+                maxCount = Integer.parseInt((String)maxCountProperty);
+            }
+        }
+
+        attachments = new LazyAttachmentCollection(this, maxCount);
+        message.setAttachments(attachments);
+    }
+
+    protected void initializeRootMessage() throws IOException {
+        String contentType = (String) message.get(Message.CONTENT_TYPE);
+
+        if (contentType == null) {
+            throw new IllegalStateException("Content-Type can not be empty!");
+        }
+
+        if (message.getContent(InputStream.class) == null) {
+            throw new IllegalStateException("An InputStream must be provided!");
+        }
+
+        if (AttachmentUtil.isTypeSupported(contentType.toLowerCase(), supportedTypes)) {
+            String boundaryString = findBoundaryFromContentType(contentType);
+            if (null == boundaryString) {
+                boundaryString = findBoundaryFromInputStream();
+            }
+            // If a boundary still wasn't found, throw an exception
+            if (null == boundaryString) {
+                throw new IOException("Couldn't determine the boundary from the message!");
+            }
+            boundary = boundaryString.getBytes(StandardCharsets.UTF_8);
+
+            stream = new PushbackInputStream(message.getContent(InputStream.class), PUSHBACK_AMOUNT);
+            if (!readTillFirstBoundary(stream, boundary)) {
+                throw new IOException("Couldn't find MIME boundary: " + boundaryString);
+            }
+
+            Map<String, List<String>> ih = loadPartHeaders(stream);
+            message.put(ATTACHMENT_PART_HEADERS, ih);
+            String val = AttachmentUtil.getHeader(ih, "Content-Type", "; ");
+            if (!StringUtils.isEmpty(val)) {
+                String cs = HttpHeaderHelper.findCharset(val);
+                if (!StringUtils.isEmpty(cs)) {
+                    message.put(Message.ENCODING, HttpHeaderHelper.mapCharset(cs));
+                }
+            }
+            val = AttachmentUtil.getHeader(ih, "Content-Transfer-Encoding");
+
+            MimeBodyPartInputStream mmps = new MimeBodyPartInputStream(stream, boundary, PUSHBACK_AMOUNT);
+            InputStream ins = AttachmentUtil.decode(mmps, val);
+            if (ins != mmps) {
+                ih.remove("Content-Transfer-Encoding");
+            }
+            body = new DelegatingInputStream(ins, this);
+            createCount++;
+            message.setContent(InputStream.class, body);
+        }
+    }
+
+    private String findBoundaryFromContentType(String ct) {
+        // Use regex to get the boundary and return null if it's not found
+        Matcher m = CONTENT_TYPE_BOUNDARY_PATTERN.matcher(ct);
+        return m.find() ? "--" + m.group(1) : null;
+    }
+
+    private String findBoundaryFromInputStream() throws IOException {
+        InputStream is = message.getContent(InputStream.class);
+        //boundary should definitely be in the first 2K;
+        PushbackInputStream in = new PushbackInputStream(is, 4096);
+        byte[] buf = new byte[2048];
+        int i = in.read(buf);
+        int len = i;
+        while (i > 0 && len < buf.length) {
+            i = in.read(buf, len, buf.length - len);
+            if (i > 0) {
+                len += i;
+            }
+        }
+        String msg = IOUtils.newStringFromBytes(buf, 0, len);
+        in.unread(buf, 0, len);
+
+        // Reset the input stream since we'll need it again later
+        message.setContent(InputStream.class, in);
+
+        // Use regex to get the boundary and return null if it's not found
+        Matcher m = INPUT_STREAM_BOUNDARY_PATTERN.matcher(msg);
+        return m.find() ? "--" + m.group(1) : null;
+    }
+
+    public AttachmentImpl readNext() throws IOException {
+        // Cache any mime parts that are currently being streamed
+        cacheStreamedAttachments();
+        if (closed) {
+            return null;
+        }
+
+        int v = stream.read();
+        if (v == -1) {
+            return null;
+        }
+        stream.unread(v);
+
+        Map<String, List<String>> headers = loadPartHeaders(stream);
+        return (AttachmentImpl)createAttachment(headers);
+    }
+
+    private void cacheStreamedAttachments() throws IOException {
+        if (body instanceof DelegatingInputStream
+            && !((DelegatingInputStream) body).isClosed()) {
+
+            cache((DelegatingInputStream) body);
+        }
+
+        List<Attachment> atts = new ArrayList<>(attachments.getLoadedAttachments());
+        for (Attachment a : atts) {
+            DataSource s = a.getDataHandler().getDataSource();
+            if (s instanceof AttachmentDataSource) {
+                AttachmentDataSource ads = (AttachmentDataSource)s;
+                if (!ads.isCached()) {
+                    ads.cache(message);
+                }
+            } else if (s.getInputStream() instanceof DelegatingInputStream) {
+                cache((DelegatingInputStream) s.getInputStream());
+            } else {
+                //assume a normal stream that is already cached
+            }
+        }
+    }
+
+    private void cache(DelegatingInputStream input) throws IOException {
+        if (loaded.contains(input)) {
+            return;
+        }
+        loaded.add(input);
+        InputStream origIn = input.getInputStream();
+        try (CachedOutputStream out = new CachedOutputStream()) {
+            AttachmentUtil.setStreamedAttachmentProperties(message, out);
+            IOUtils.copy(input, out);
+            input.setInputStream(out.getInputStream());
+            origIn.close();
+        }
+    }
+
+    /**
+     * Move the read pointer to the begining of the first part read till the end
+     * of first boundary
+     *
+     * @param pushbackInStream
+     * @param boundary
+     * @throws IOException
+     */
+    private static boolean readTillFirstBoundary(PushbackInputStream pushbackInStream,
+        byte[] boundary) throws IOException {
+
+        // work around a bug in PushBackInputStream where the buffer isn't
+        // initialized
+        // and available always returns 0.
+        int value = pushbackInStream.read();
+        pushbackInStream.unread(value);
+        while (value != -1) {
+            value = pushbackInStream.read();
+            if ((byte) value == boundary[0]) {
+                int boundaryIndex = 0;
+                while (value != -1 && (boundaryIndex < boundary.length) && ((byte) value == boundary[boundaryIndex])) {
+
+                    value = pushbackInStream.read();
+                    if (value == -1) {
+                        throw new IOException("Unexpected End while searching for first Mime Boundary");
+                    }
+                    boundaryIndex++;
+                }
+                if (boundaryIndex == boundary.length) {
+                    // boundary found, read the newline
+                    if (value == 13) {
+                        pushbackInStream.read();
+                    }
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Create an Attachment from the MIME stream. If there is a previous attachment
+     * that is not read, cache that attachment.
+     *
+     * @throws IOException
+     */
+    private Attachment createAttachment(Map<String, List<String>> headers) throws IOException {
+        InputStream partStream =
+            new DelegatingInputStream(new MimeBodyPartInputStream(stream, boundary, PUSHBACK_AMOUNT),
+                                      this);
+        createCount++;
+
+        return AttachmentUtil.createAttachment(partStream, headers);
+    }
+
+    public boolean isLazyLoading() {
+        return lazyLoading;
+    }
+
+    public void setLazyLoading(boolean lazyLoading) {
+        this.lazyLoading = lazyLoading;
+    }
+
+    public void markClosed(DelegatingInputStream delegatingInputStream) throws IOException {
+        closedCount++;
+        if (closedCount == createCount && !attachments.hasNext(false)) {
+            int x = stream.read();
+            while (x != -1) {
+                x = stream.read();
+            }
+            stream.close();
+            closed = true;
+        }
+    }
+    /**
+     *  Check for more attachment.
+     *
+     * @return whether there is more attachment or not.  It will not deserialize the next attachment.
+     * @throws IOException
+     */
+    public boolean hasNext() throws IOException {
+        cacheStreamedAttachments();
+        if (closed) {
+            return false;
+        }
+
+        int v = stream.read();
+        if (v == -1) {
+            return false;
+        }
+        stream.unread(v);
+        return true;
+    }
+
+
+
+    private Map<String, List<String>> loadPartHeaders(InputStream in) throws IOException {
+        StringBuilder buffer = new StringBuilder(128);
+        StringBuilder b = new StringBuilder(128);
+        Map<String, List<String>> heads = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+
+        // loop until we hit the end or a null line
+        while (readLine(in, b)) {
+            // lines beginning with white space get special handling
+            char c = b.charAt(0);
+            if (c == ' ' || c == '\t') {
+                if (buffer.length() != 0) {
+                    // preserve the line break and append the continuation
+                    buffer.append("\r\n");
+                    buffer.append(b);
+                }
+            } else {
+                // if we have a line pending in the buffer, flush it
+                if (buffer.length() > 0) {
+                    addHeaderLine(heads, buffer);
+                    buffer.setLength(0);
+                }
+                // add this to the accumulator
+                buffer.append(b);
+            }
+        }
+
+        // if we have a line pending in the buffer, flush it
+        if (buffer.length() > 0) {
+            addHeaderLine(heads, buffer);
+        }
+        return heads;
+    }
+
+    private boolean readLine(InputStream in, StringBuilder buffer) throws IOException {
+        if (buffer.length() != 0) {
+            buffer.setLength(0);
+        }
+        int c;
+
+        while ((c = in.read()) != -1) {
+            // a linefeed is a terminator, always.
+            if (c == '\n') {
+                break;
+            } else if (c == '\r') {
+                //just ignore the CR.  The next character SHOULD be an NL.  If not, we're
+                //just going to discard this
+                continue;
+            } else {
+                // just add to the buffer
+                buffer.append((char)c);
+            }
+
+            if (buffer.length() > maxHeaderLength) {
+                LOG.fine("The attachment header size has exceeded the configured parameter: " + maxHeaderLength);
+                throw new HeaderSizeExceededException();
+            }
+        }
+
+        // no characters found...this was either an eof or a null line.
+        return buffer.length() != 0;
+    }
+
+    private void addHeaderLine(Map<String, List<String>> heads, StringBuilder line) {
+        // null lines are a nop
+        final int size = line.length();
+        if (size == 0) {
+            return;
+        }
+        int separator = line.indexOf(":");
+        final String name;
+        String value = "";
+        if (separator == -1) {
+            name = line.toString().trim();
+        } else {
+            name = line.substring(0, separator);
+            // step past the separator.  Now we need to remove any leading white space characters.
+            separator++;
+
+            while (separator < size) {
+                char ch = line.charAt(separator);
+                if (ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n') {
+                    break;
+                }
+                separator++;
+            }
+            value = line.substring(separator);
+        }
+        List<String> v = heads.computeIfAbsent(name, k -> new ArrayList<>(1));
+        v.add(value);
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/AttachmentSerializer.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/AttachmentSerializer.java
new file mode 100644
index 0000000000..e1fc0abd3d
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/AttachmentSerializer.java
@@ -0,0 +1,345 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.attachment;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import jakarta.activation.DataHandler;
+
+import org.apache.cxf.common.util.Base64Utility;
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.message.Attachment;
+import org.apache.cxf.message.Message;
+
+
+
+
+public class AttachmentSerializer {
+    // http://tools.ietf.org/html/rfc2387
+    private static final String DEFAULT_MULTIPART_TYPE = "multipart/related";
+
+    private String contentTransferEncoding = AttachmentUtil.BINARY;
+
+    private Message message;
+    private String bodyBoundary;
+    private OutputStream out;
+    private String encoding;
+
+    private String multipartType;
+    private Map<String, List<String>> rootHeaders = Collections.emptyMap();
+    private boolean xop = true;
+    private boolean writeOptionalTypeParameters = true;
+
+
+    public AttachmentSerializer(Message messageParam) {
+        message = messageParam;
+    }
+
+    public AttachmentSerializer(Message messageParam,
+                                String multipartType,
+                                boolean writeOptionalTypeParameters,
+                                Map<String, List<String>> headers) {
+        message = messageParam;
+        this.multipartType = multipartType;
+        this.writeOptionalTypeParameters = writeOptionalTypeParameters;
+        this.rootHeaders = headers;
+    }
+
+    /**
+     * Serialize the beginning of the attachment which includes the MIME
+     * beginning and headers for the root message.
+     */
+    public void writeProlog() throws IOException {
+        // Create boundary for body
+        bodyBoundary = AttachmentUtil.getUniqueBoundaryValue();
+
+        String bodyCt = (String) message.get(Message.CONTENT_TYPE);
+        String bodyCtParams = null;
+        String bodyCtParamsEscaped = null;
+        // split the bodyCt to its head that is the type and its properties so that we
+        // can insert the values at the right places based on the soap version and the mtom option
+        // bodyCt will be of the form
+        // soap11 -> text/xml
+        // soap12 -> application/soap+xml; action="urn:ihe:iti:2007:RetrieveDocumentSet"
+        if (bodyCt.indexOf(';') != -1) {
+            int pos = bodyCt.indexOf(';');
+            // get everything from the semi-colon
+            bodyCtParams = bodyCt.substring(pos);
+            bodyCtParamsEscaped = escapeQuotes(bodyCtParams);
+            // keep the type/subtype part in bodyCt
+            bodyCt = bodyCt.substring(0, pos);
+        }
+        // Set transport mime type
+        String requestMimeType = multipartType == null ? DEFAULT_MULTIPART_TYPE : multipartType;
+
+        StringBuilder ct = new StringBuilder(32);
+        ct.append(requestMimeType);
+
+        // having xop set to true implies multipart/related, but just in case...
+        boolean xopOrMultipartRelated = xop
+            || DEFAULT_MULTIPART_TYPE.equalsIgnoreCase(requestMimeType)
+            || DEFAULT_MULTIPART_TYPE.startsWith(requestMimeType);
+
+        // type is a required parameter for multipart/related only
+        if (xopOrMultipartRelated
+            && requestMimeType.indexOf("type=") == -1) {
+            if (xop) {
+                ct.append("; type=\"application/xop+xml\"");
+            } else {
+                ct.append("; type=\"").append(bodyCt).append('"');
+            }
+        }
+
+        // boundary
+        ct.append("; boundary=\"")
+            .append(bodyBoundary)
+            .append('"');
+
+        String rootContentId = getHeaderValue("Content-ID", AttachmentUtil.BODY_ATTACHMENT_ID);
+
+        // 'start' is a required parameter for XOP/MTOM, clearly defined
+        // for simpler multipart/related payloads but is not needed for
+        // multipart/mixed, multipart/form-data
+        if (xopOrMultipartRelated) {
+            ct.append("; start=\"<")
+                .append(checkAngleBrackets(rootContentId))
+                .append(">\"");
+        }
+
+        // start-info is a required parameter for XOP/MTOM, may be needed for
+        // other WS cases but is redundant in simpler multipart/related cases
+        // the parameters need to be included within the start-info's value in the escaped form
+        if (writeOptionalTypeParameters || xop) {
+            ct.append("; start-info=\"")
+                .append(bodyCt);
+            if (bodyCtParamsEscaped != null) {
+                ct.append(bodyCtParamsEscaped);
+            }
+            ct.append('"');
+        }
+
+
+        message.put(Message.CONTENT_TYPE, ct.toString());
+
+
+        // 2. write headers
+        out = message.getContent(OutputStream.class);
+        encoding = (String) message.get(Message.ENCODING);
+        if (encoding == null) {
+            encoding = StandardCharsets.UTF_8.name();
+        }
+        StringWriter writer = new StringWriter();
+        writer.write("\r\n");
+        writer.write("--");
+        writer.write(bodyBoundary);
+
+        StringBuilder mimeBodyCt = new StringBuilder();
+        String bodyType = getHeaderValue("Content-Type", null);
+        if (bodyType == null) {
+            mimeBodyCt.append(xop ? "application/xop+xml" : bodyCt)
+                .append("; charset=").append(encoding);
+            if (xop) {
+                mimeBodyCt.append("; type=\"").append(bodyCt);
+                if (bodyCtParamsEscaped != null) {
+                    mimeBodyCt.append(bodyCtParamsEscaped);
+                }
+                mimeBodyCt.append('"');
+            } else if (bodyCtParams != null) {
+                mimeBodyCt.append(bodyCtParams);
+            }
+        } else {
+            mimeBodyCt.append(bodyType);
+        }
+
+        writeHeaders(mimeBodyCt.toString(), rootContentId, rootHeaders, writer);
+        out.write(writer.getBuffer().toString().getBytes(encoding));
+    }
+
+    private static String escapeQuotes(String s) {
+        return s.indexOf('"') != 0 ? s.replace("\"", "\\\"") : s;
+    }
+
+    public void setContentTransferEncoding(String cte) {
+        contentTransferEncoding = cte;
+    }
+
+    private String getHeaderValue(String name, String defaultValue) {
+        List<String> value = rootHeaders.get(name);
+        if (value == null || value.isEmpty()) {
+            return defaultValue;
+        }
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < value.size(); i++) {
+            sb.append(value.get(i));
+            if (i + 1 < value.size()) {
+                sb.append(',');
+            }
+        }
+        return sb.toString();
+    }
+
+    private void writeHeaders(String contentType, String attachmentId,
+                                     Map<String, List<String>> headers, Writer writer) throws IOException {
+        writer.write("\r\nContent-Type: ");
+        writer.write(contentType);
+        writer.write("\r\nContent-Transfer-Encoding: " + contentTransferEncoding + "\r\n");
+
+        if (attachmentId != null) {
+            attachmentId = checkAngleBrackets(attachmentId);
+            writer.write("Content-ID: <");
+            writer.write(URLDecoder.decode(attachmentId, StandardCharsets.UTF_8.name()));
+            writer.write(">\r\n");
+        }
+        // headers like Content-Disposition need to be serialized
+        for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
+            String name = entry.getKey();
+            if ("Content-Type".equalsIgnoreCase(name) || "Content-ID".equalsIgnoreCase(name)
+                || "Content-Transfer-Encoding".equalsIgnoreCase(name)) {
+                continue;
+            }
+            writer.write(name);
+            writer.write(": ");
+            List<String> values = entry.getValue();
+            for (int i = 0; i < values.size(); i++) {
+                writer.write(values.get(i));
+                if (i + 1 < values.size()) {
+                    writer.write(",");
+                }
+            }
+            writer.write("\r\n");
+        }
+
+        writer.write("\r\n");
+    }
+
+    private static String checkAngleBrackets(String value) {
+        if (value.charAt(0) == '<' && value.charAt(value.length() - 1) == '>') {
+            return value.substring(1, value.length() - 1);
+        }
+        return value;
+    }
+
+    /**
+     * Write the end of the body boundary and any attachments included.
+     * @throws IOException
+     */
+    public void writeAttachments() throws IOException {
+        if (message.getAttachments() != null) {
+            for (Attachment a : message.getAttachments()) {
+                StringWriter writer = new StringWriter();
+                writer.write("\r\n--");
+                writer.write(bodyBoundary);
+
+                final Map<String, List<String>> headers;
+                Iterator<String> it = a.getHeaderNames();
+                if (it.hasNext()) {
+                    headers = new LinkedHashMap<>();
+                    while (it.hasNext()) {
+                        String key = it.next();
+                        headers.put(key, Collections.singletonList(a.getHeader(key)));
+                    }
+                } else {
+                    headers = Collections.emptyMap();
+                }
+
+
+                DataHandler handler = a.getDataHandler();
+                handler.setCommandMap(AttachmentUtil.getCommandMap());
+
+                writeHeaders(handler.getContentType(), a.getId(),
+                             headers, writer);
+                out.write(writer.getBuffer().toString().getBytes(encoding));
+                if ("base64".equals(contentTransferEncoding)) {
+                    try (InputStream inputStream = handler.getInputStream()) {
+                        encodeBase64(inputStream, out, IOUtils.DEFAULT_BUFFER_SIZE);
+                    }
+                } else {
+                    handler.writeTo(out);
+                }
+            }
+        }
+        StringWriter writer = new StringWriter();
+        writer.write("\r\n--");
+        writer.write(bodyBoundary);
+        writer.write("--");
+        out.write(writer.getBuffer().toString().getBytes(encoding));
+        out.flush();
+    }
+
+    private int encodeBase64(InputStream input, OutputStream output, int bufferSize) throws IOException {
+        int avail = input.available();
+        if (avail > 262143) {
+            //must be divisible by 3
+            avail = 262143;
+        }
+        if (avail > bufferSize) {
+            bufferSize = avail;
+        }
+        final byte[] buffer = new byte[bufferSize];
+        int n = input.read(buffer);
+        int total = 0;
+        while (-1 != n) {
+            if (n == 0) {
+                throw new IOException("0 bytes read in violation of InputStream.read(byte[])");
+            }
+            //make sure n is divisible by 3
+            int left = n % 3;
+            n -= left;
+            if (n > 0) {
+                Base64Utility.encodeAndStream(buffer, 0, n, output);
+                total += n;
+            }
+            if (left != 0) {
+                for (int x = 0; x < left; ++x) {
+                    buffer[x] = buffer[n + x];
+                }
+                n = input.read(buffer, left, buffer.length - left);
+                if (n == -1) {
+                    // we've hit the end, but still have stuff left, write it out
+                    Base64Utility.encodeAndStream(buffer, 0, left, output);
+                    total += left;
+                }
+            } else {
+                n = input.read(buffer);
+            }
+        }
+        return total;
+    }
+
+    public boolean isXop() {
+        return xop;
+    }
+
+    public void setXop(boolean xop) {
+        this.xop = xop;
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/AttachmentUtil.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/AttachmentUtil.java
new file mode 100644
index 0000000000..bb53347dcd
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/AttachmentUtil.java
@@ -0,0 +1,572 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.attachment;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Logger;
+
+import jakarta.activation.CommandInfo;
+import jakarta.activation.CommandMap;
+import jakarta.activation.DataContentHandler;
+import jakarta.activation.DataHandler;
+import jakarta.activation.DataSource;
+import jakarta.activation.FileDataSource;
+import jakarta.activation.MailcapCommandMap;
+import jakarta.activation.URLDataSource;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.helpers.FileUtils;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.io.CachedOutputStream;
+import org.apache.cxf.message.Attachment;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageUtils;
+
+public final class AttachmentUtil {
+    public static final String BODY_ATTACHMENT_ID = "root.message@cxf.apache.org";
+
+    static final String BINARY = "binary";
+    
+    private static final Logger LOG = LogUtils.getL7dLogger(AttachmentUtil.class);
+
+    private static final AtomicInteger COUNTER = new AtomicInteger();
+    private static final String ATT_UUID = UUID.randomUUID().toString();
+
+    private static final Random BOUND_RANDOM = new Random();
+    private static final CommandMap DEFAULT_COMMAND_MAP = CommandMap.getDefaultCommandMap();
+    private static final MailcapCommandMap COMMAND_MAP = new EnhancedMailcapCommandMap();
+    
+    
+    static final class EnhancedMailcapCommandMap extends MailcapCommandMap {
+        @Override
+        public synchronized DataContentHandler createDataContentHandler(
+                String mimeType) {
+            DataContentHandler dch = super.createDataContentHandler(mimeType);
+            if (dch == null) {
+                dch = DEFAULT_COMMAND_MAP.createDataContentHandler(mimeType);
+            }
+            return dch;
+        }
+
+        @Override
+        public DataContentHandler createDataContentHandler(String mimeType,
+                DataSource ds) {
+            DataContentHandler dch = super.createDataContentHandler(mimeType);
+            if (dch == null) {
+                dch = DEFAULT_COMMAND_MAP.createDataContentHandler(mimeType, ds);
+            }
+            return dch;
+        }
+
+        @Override
+        public synchronized CommandInfo[] getAllCommands(String mimeType) {
+            CommandInfo[] commands = super.getAllCommands(mimeType);
+            CommandInfo[] defaultCommands = DEFAULT_COMMAND_MAP.getAllCommands(mimeType);
+            List<CommandInfo> cmdList = new ArrayList<>(Arrays.asList(commands));
+
+            // Add CommandInfo which does not exist in current command map.
+            for (CommandInfo defCmdInfo : defaultCommands) {
+                String defCmdName = defCmdInfo.getCommandName();
+                boolean cmdNameExist = false;
+                for (CommandInfo cmdInfo : commands) {
+                    if (cmdInfo.getCommandName().equals(defCmdName)) {
+                        cmdNameExist = true;
+                        break;
+                    }
+                }
+                if (!cmdNameExist) {
+                    cmdList.add(defCmdInfo);
+                }
+            }
+
+            CommandInfo[] allCommandArray = new CommandInfo[0];
+            return cmdList.toArray(allCommandArray);
+        }
+
+        @Override
+        public synchronized CommandInfo getCommand(String mimeType, String cmdName) {
+            CommandInfo cmdInfo = super.getCommand(mimeType, cmdName);
+            if (cmdInfo == null) {
+                cmdInfo = DEFAULT_COMMAND_MAP.getCommand(mimeType, cmdName);
+            }
+            return cmdInfo;
+        }
+
+        /**
+         * Merge current mime types and default mime types.
+         */
+        @Override
+        public synchronized String[] getMimeTypes() {
+            String[] mimeTypes = super.getMimeTypes();
+            String[] defMimeTypes = DEFAULT_COMMAND_MAP.getMimeTypes();
+            Set<String> mimeTypeSet = new HashSet<>();
+            Collections.addAll(mimeTypeSet, mimeTypes);
+            Collections.addAll(mimeTypeSet, defMimeTypes);
+            String[] mimeArray = new String[0];
+            return mimeTypeSet.toArray(mimeArray);
+        }
+    }
+
+
+    private AttachmentUtil() {
+
+    }
+
+    static {
+        COMMAND_MAP.addMailcap("image/*;;x-java-content-handler="
+                               + ImageDataContentHandler.class.getName());
+    }
+
+    public static CommandMap getCommandMap() {
+        return COMMAND_MAP;
+    }
+
+    public static boolean isMtomEnabled(Message message) {
+        return MessageUtils.getContextualBoolean(message, Message.MTOM_ENABLED, false);
+    }
+
+    public static void setStreamedAttachmentProperties(Message message, CachedOutputStream bos)
+        throws IOException {
+        Object directory = message.getContextualProperty(AttachmentDeserializer.ATTACHMENT_DIRECTORY);
+        if (directory != null) {
+            if (directory instanceof File) {
+                bos.setOutputDir((File) directory);
+            } else if (directory instanceof String) {
+                bos.setOutputDir(new File((String) directory));
+            } else {
+                throw new IOException("The value set as " + AttachmentDeserializer.ATTACHMENT_DIRECTORY
+                        + " should be either an instance of File or String");
+            }
+        }
+
+        Object threshold = message.getContextualProperty(AttachmentDeserializer.ATTACHMENT_MEMORY_THRESHOLD);
+        if (threshold != null) {
+            if (threshold instanceof Number) {
+                long t = ((Number) threshold).longValue();
+                if (t >= 0) {
+                    bos.setThreshold(t);
+                } else {
+                    LOG.warning("Threshold value overflowed long. Setting default value!");
+                    bos.setThreshold(AttachmentDeserializer.THRESHOLD);
+                }
+            } else if (threshold instanceof String) {
+                try {
+                    bos.setThreshold(Long.parseLong((String) threshold));
+                } catch (NumberFormatException e) {
+                    throw new IOException("Provided threshold String is not a number", e);
+                }
+            } else {
+                throw new IOException("The value set as " + AttachmentDeserializer.ATTACHMENT_MEMORY_THRESHOLD
+                        + " should be either an instance of Number or String");
+            }
+        } else if (!CachedOutputStream.isThresholdSysPropSet()) {
+            // Use the default AttachmentDeserializer Threshold only if there is no system property defined
+            bos.setThreshold(AttachmentDeserializer.THRESHOLD);
+        }
+
+        Object maxSize = message.getContextualProperty(AttachmentDeserializer.ATTACHMENT_MAX_SIZE);
+        if (maxSize != null) {
+            if (maxSize instanceof Number) {
+                long size = ((Number) maxSize).longValue();
+                if (size >= 0) {
+                    bos.setMaxSize(size);
+                } else {
+                    LOG.warning("Max size value overflowed long. Do not set max size!");
+                }
+            } else if (maxSize instanceof String) {
+                try {
+                    bos.setMaxSize(Long.parseLong((String) maxSize));
+                } catch (NumberFormatException e) {
+                    throw new IOException("Provided threshold String is not a number", e);
+                }
+            } else {
+                throw new IOException("The value set as " + AttachmentDeserializer.ATTACHMENT_MAX_SIZE
+                        + " should be either an instance of Number or String");
+            }
+        }
+    }
+
+    public static String createContentID(String ns) throws UnsupportedEncodingException {
+        // tend to change
+        String cid = "cxf.apache.org";
+        if (ns != null && !ns.isEmpty()) {
+            try {
+                URI uri = new URI(ns);
+                String host = uri.getHost();
+                if (host != null) {
+                    cid = host;
+                } else {
+                    cid = ns;
+                }
+            } catch (Exception e) {
+                cid = ns;
+            }
+        }
+        return ATT_UUID + '-' + Integer.toString(COUNTER.incrementAndGet()) + '@'
+            + URLEncoder.encode(cid, StandardCharsets.UTF_8.name());
+    }
+
+    public static String getUniqueBoundaryValue() {
+        //generate a random UUID.
+        //we don't need the cryptographically secure random uuid that
+        //UUID.randomUUID() will produce.  Thus, use a faster
+        //pseudo-random thing
+        long leastSigBits;
+        long mostSigBits;
+        synchronized (BOUND_RANDOM) {
+            mostSigBits = BOUND_RANDOM.nextLong();
+            leastSigBits = BOUND_RANDOM.nextLong();
+        }
+
+        mostSigBits &= 0xFFFFFFFFFFFF0FFFL;  //clear version
+        mostSigBits |= 0x0000000000004000L;  //set version
+
+        leastSigBits &= 0x3FFFFFFFFFFFFFFFL; //clear the variant
+        leastSigBits |= 0x8000000000000000L; //set to IETF variant
+
+        UUID result = new UUID(mostSigBits, leastSigBits);
+
+        return "uuid:" + result.toString();
+    }
+
+    public static Map<String, DataHandler> getDHMap(final Collection<Attachment> attachments) {
+        Map<String, DataHandler> dataHandlers = null;
+        if (attachments != null) {
+            if (attachments instanceof LazyAttachmentCollection) {
+                dataHandlers = ((LazyAttachmentCollection)attachments).createDataHandlerMap();
+            } else {
+                dataHandlers = new DHMap(attachments);
+            }
+        }
+        return dataHandlers == null ? new LinkedHashMap<>() : dataHandlers;
+    }
+
+    static class DHMap extends AbstractMap<String, DataHandler> {
+        final Collection<Attachment> list;
+        DHMap(Collection<Attachment> l) {
+            list = l;
+        }
+        public Set<Map.Entry<String, DataHandler>> entrySet() {
+            return new AbstractSet<Map.Entry<String, DataHandler>>() {
+                @Override
+                public Iterator<Map.Entry<String, DataHandler>> iterator() {
+                    final Iterator<Attachment> it = list.iterator();
+                    return new Iterator<Map.Entry<String, DataHandler>>() {
+                        public boolean hasNext() {
+                            return it.hasNext();
+                        }
+                        public Map.Entry<String, DataHandler> next() {
+                            final Attachment a = it.next();
+                            return new Map.Entry<String, DataHandler>() {
+                                @Override
+                                public String getKey() {
+                                    return a.getId();
+                                }
+
+                                @Override
+                                public DataHandler getValue() {
+                                    return a.getDataHandler();
+                                }
+
+                                @Override
+                                public DataHandler setValue(DataHandler value) {
+                                    return null;
+                                }
+                            };
+                        }
+                        @Override
+                        public void remove() {
+                            it.remove();
+                        }
+                    };
+                }
+
+                @Override
+                public int size() {
+                    return list.size();
+                }
+            };
+        }
+        
+        @Override
+        public DataHandler put(String key, DataHandler value) {
+            Iterator<Attachment> i = list.iterator();
+            DataHandler ret = null;
+            while (i.hasNext()) {
+                Attachment a = i.next();
+                if (a.getId().equals(key)) {
+                    i.remove();
+                    ret = a.getDataHandler();
+                    break;
+                }
+            }
+            list.add(new AttachmentImpl(key, value));
+            return ret;
+        }
+    }
+
+    public static String cleanContentId(String id) {
+        if (id != null) {
+            if (id.startsWith("<")) {
+                // strip <>
+                id = id.substring(1, id.length() - 1);
+            }
+            // strip cid:
+            if (id.startsWith("cid:")) {
+                id = id.substring(4);
+            }
+            // urldecode. Is this bad even without cid:? What does decode do with malformed %-signs, anyhow?
+            try {
+                id = URLDecoder.decode(id, StandardCharsets.UTF_8.name());
+            } catch (UnsupportedEncodingException e) {
+                //ignore, keep id as is
+            }
+        }
+        if (id == null) {
+            //no Content-ID, set cxf default ID
+            id =  BODY_ATTACHMENT_ID;
+        }
+        return id;
+    }
+
+    static String getHeaderValue(List<String> v) {
+        if (v != null && !v.isEmpty()) {
+            return v.get(0);
+        }
+        return null;
+    }
+    static String getHeaderValue(List<String> v, String delim) {
+        if (v != null && !v.isEmpty()) {
+            return String.join(delim, v);
+        }
+        return null;
+    }
+    static String getHeader(Map<String, List<String>> headers, String h) {
+        return getHeaderValue(headers.get(h));
+    }
+    static String getHeader(Map<String, List<String>> headers, String h, String delim) {
+        return getHeaderValue(headers.get(h), delim);
+    }
+    public static Attachment createAttachment(InputStream stream, Map<String, List<String>> headers)
+        throws IOException {
+
+        String id = cleanContentId(getHeader(headers, "Content-ID"));
+
+        AttachmentImpl att = new AttachmentImpl(id);
+
+        final String ct = getHeader(headers, "Content-Type");
+        String cd = getHeader(headers, "Content-Disposition");
+        String fileName = getContentDispositionFileName(cd);
+
+        String encoding = null;
+
+        for (Map.Entry<String, List<String>> e : headers.entrySet()) {
+            String name = e.getKey();
+            if ("Content-Transfer-Encoding".equalsIgnoreCase(name)) {
+                encoding = getHeader(headers, name);
+                if (BINARY.equalsIgnoreCase(encoding)) {
+                    att.setXOP(true);
+                }
+            }
+            att.setHeader(name, getHeaderValue(e.getValue()));
+        }
+        if (encoding == null) {
+            encoding = BINARY;
+        }
+        InputStream ins = decode(stream, encoding);
+        if (ins != stream) {
+            headers.remove("Content-Transfer-Encoding");
+        }
+        DataSource source = new AttachmentDataSource(ct, ins);
+        if (!StringUtils.isEmpty(fileName)) {
+            ((AttachmentDataSource)source).setName(FileUtils.stripPath(fileName));
+        }
+        att.setDataHandler(new DataHandler(source));
+        return att;
+    }
+
+    static String getContentDispositionFileName(String cd) {
+        if (StringUtils.isEmpty(cd)) {
+            return null;
+        }
+        ContentDisposition c = new ContentDisposition(cd);
+        String s = c.getParameter("filename");
+        if (s == null) {
+            s = c.getParameter("name");
+        }
+        return s;
+    }
+
+    public static InputStream decode(InputStream in, String encoding) throws IOException {
+        if (encoding == null) {
+            return in;
+        }
+        encoding = encoding.toLowerCase();
+
+        // some encodings are just pass-throughs, with no real decoding.
+        if (BINARY.equals(encoding)
+            || "7bit".equals(encoding)
+            || "8bit".equals(encoding)) {
+            return in;
+        } else if ("base64".equals(encoding)) {
+            return new Base64DecoderStream(in);
+        } else if ("quoted-printable".equals(encoding)) {
+            return new QuotedPrintableDecoderStream(in);
+        } else {
+            throw new IOException("Unknown encoding " + encoding);
+        }
+    }
+    public static boolean isTypeSupported(String contentType, List<String> types) {
+        if (contentType == null) {
+            return false;
+        }
+        contentType = contentType.toLowerCase();
+        for (String s : types) {
+            if (contentType.indexOf(s) != -1) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static Attachment createMtomAttachment(boolean isXop, String mimeType, String elementNS,
+                                                 byte[] data, int offset, int length, int threshold) {
+        if (!isXop || length <= threshold) {
+            return null;
+        }
+        if (mimeType == null) {
+            mimeType = "application/octet-stream";
+        }
+
+        ByteDataSource source = new ByteDataSource(data, offset, length);
+        source.setContentType(mimeType);
+        DataHandler handler = new DataHandler(source);
+
+        String id;
+        try {
+            id = AttachmentUtil.createContentID(elementNS);
+        } catch (UnsupportedEncodingException e) {
+            throw new Fault(e);
+        }
+        AttachmentImpl att = new AttachmentImpl(id, handler);
+        att.setXOP(isXop);
+        return att;
+    }
+
+    public static Attachment createMtomAttachmentFromDH(
+        boolean isXop, DataHandler handler, String elementNS, int threshold) {
+        if (!isXop) {
+            return null;
+        }
+
+        // The following is just wrong. Even if the DataHandler has a stream, we should still
+        // apply the threshold.
+        try {
+            DataSource ds = handler.getDataSource();
+            if (ds instanceof FileDataSource) {
+                FileDataSource fds = (FileDataSource)ds;
+                File file = fds.getFile();
+                if (file.length() < threshold) {
+                    return null;
+                }
+            } else if (ds.getClass().getName().endsWith("ObjectDataSource")) {
+                Object o = handler.getContent();
+                if (o instanceof String
+                    && ((String)o).length() < threshold) {
+                    return null;
+                } else if (o instanceof byte[] && ((byte[])o).length < threshold) {
+                    return null;
+                }
+            }
+        } catch (IOException e1) {
+        //      ignore, just do the normal attachment thing
+        }
+
+        String id;
+        try {
+            id = AttachmentUtil.createContentID(elementNS);
+        } catch (UnsupportedEncodingException e) {
+            throw new Fault(e);
+        }
+        AttachmentImpl att = new AttachmentImpl(id, handler);
+        if (!StringUtils.isEmpty(handler.getName())) {
+            //set Content-Disposition attachment header if filename isn't null
+            String file = handler.getName();
+            File f = new File(file);
+            if (f.exists() && f.isFile()) {
+                file = f.getName();
+            }
+            att.setHeader("Content-Disposition", "attachment;name=\"" + file + "\"");
+        }
+        att.setXOP(isXop);
+        return att;
+    }
+
+    public static DataSource getAttachmentDataSource(String contentId, Collection<Attachment> atts) {
+        // Is this right? - DD
+        if (contentId.startsWith("cid:")) {
+            try {
+                contentId = URLDecoder.decode(contentId.substring(4), StandardCharsets.UTF_8.name());
+            } catch (UnsupportedEncodingException ue) {
+                contentId = contentId.substring(4);
+            }
+            return loadDataSource(contentId, atts);
+        } else if (contentId.indexOf("://") == -1) {
+            return loadDataSource(contentId, atts);
+        } else {
+            try {
+                return new URLDataSource(new URL(contentId));
+            } catch (MalformedURLException e) {
+                throw new Fault(e);
+            }
+        }
+
+    }
+
+    private static DataSource loadDataSource(String contentId, Collection<Attachment> atts) {
+        return new LazyDataSource(contentId, atts);
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/Base64DecoderStream.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/Base64DecoderStream.java
new file mode 100644
index 0000000000..134553fa27
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/Base64DecoderStream.java
@@ -0,0 +1,196 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.attachment;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.cxf.common.util.Base64Exception;
+import org.apache.cxf.common.util.Base64Utility;
+
+/**
+ * An implementation of a FilterInputStream that decodes the
+ * stream data in BASE64 encoding format.  This version does the
+ * decoding "on the fly" rather than decoding a single block of
+ * data.  Since this version is intended for use by the MimeUtilty class,
+ * it also handles line breaks in the encoded data.
+ */
+public class Base64DecoderStream extends FilterInputStream {
+
+    static final String MAIL_BASE64_IGNOREERRORS = "mail.mime.base64.ignoreerrors";
+
+    // number of decodeable units we'll try to process at one time.  We'll attempt to read that much
+    // data from the input stream and decode in blocks.
+    static final int BUFFERED_UNITS = 2000;
+
+    // can be overridden by a system property.
+    protected boolean ignoreErrors;
+
+    // buffer for reading in chars for decoding (which can support larger bulk reads)
+    protected char[] encodedChars = new char[BUFFERED_UNITS * 4];
+    // a buffer for one decoding unit's worth of data (3 bytes).
+    protected byte[] decodedChars;
+    // count of characters in the buffer
+    protected int decodedCount;
+    // index of the next decoded character
+    protected int decodedIndex;
+
+
+    public Base64DecoderStream(InputStream in) {
+        super(in);
+    }
+
+    /**
+     * Test for the existance of decoded characters in our buffer
+     * of decoded data.
+     *
+     * @return True if we currently have buffered characters.
+     */
+    private boolean dataAvailable() {
+        return decodedCount != 0;
+    }
+
+    /**
+     * Decode a requested number of bytes of data into a buffer.
+     *
+     * @return true if we were able to obtain more data, false otherwise.
+     */
+    private boolean decodeStreamData() throws IOException {
+        decodedIndex = 0;
+
+        // fill up a data buffer with input data
+        int readCharacters = fillEncodedBuffer();
+
+        if (readCharacters > 0) {
+            try {
+                decodedChars = Base64Utility.decodeChunk(encodedChars, 0, readCharacters);
+            } catch (Base64Exception e) {
+                throw new IOException(e);
+            }
+            decodedCount = decodedChars.length;
+            return true;
+        }
+        return false;
+    }
+
+
+    /**
+     * Retrieve a single byte from the decoded characters buffer.
+     *
+     * @return The decoded character or -1 if there was an EOF condition.
+     */
+    private int getByte() throws IOException {
+        if (!dataAvailable() && !decodeStreamData()) {
+            return -1;
+        }
+        decodedCount--;
+        // we need to ensure this doesn't get sign extended
+        return decodedChars[decodedIndex++] & 0xff;
+    }
+
+    private int getBytes(byte[] data, int offset, int length) throws IOException {
+
+        int readCharacters = 0;
+        while (length > 0) {
+            // need data?  Try to get some
+            if (!dataAvailable() && !decodeStreamData()) {
+                // if we can't get this, return a count of how much we did get (which may be -1).
+                return readCharacters > 0 ? readCharacters : -1;
+            }
+
+            // now copy some of the data from the decoded buffer to the target buffer
+            int copyCount = Math.min(decodedCount, length);
+            System.arraycopy(decodedChars, decodedIndex, data, offset, copyCount);
+            decodedIndex += copyCount;
+            decodedCount -= copyCount;
+            offset += copyCount;
+            length -= copyCount;
+            readCharacters += copyCount;
+        }
+        return readCharacters;
+    }
+
+
+    /**
+     * Fill our buffer of input characters for decoding from the
+     * stream.  This will attempt read a full buffer, but will
+     * terminate on an EOF or read error.  This will filter out
+     * non-Base64 encoding chars and will only return a valid
+     * multiple of 4 number of bytes.
+     *
+     * @return The count of characters read.
+     */
+    private int fillEncodedBuffer() throws IOException {
+        int readCharacters = 0;
+
+        while (true) {
+            // get the next character from the stream
+            int ch = in.read();
+            // did we hit an EOF condition?
+            if (ch == -1) {
+                // now check to see if this is normal, or potentially an error
+                // if we didn't get characters as a multiple of 4, we may need to complain about this.
+                if ((readCharacters % 4) != 0) {
+                    throw new IOException("Base64 encoding error, data truncated: " + readCharacters + " "
+                                          + new String(encodedChars, 0, readCharacters));
+                }
+                // return the count.
+                return readCharacters;
+            } else if (Base64Utility.isValidBase64(ch)) {
+                // if this character is valid in a Base64 stream, copy it to the buffer.
+                encodedChars[readCharacters++] = (char)ch;
+                // if we've filled up the buffer, time to quit.
+                if (readCharacters >= encodedChars.length) {
+                    return readCharacters;
+                }
+            }
+
+            // we're filtering out whitespace and CRLF characters, so just ignore these
+        }
+    }
+
+
+    // in order to function as a filter, these streams need to override the different
+    // read() signature.
+
+    @Override
+    public int read() throws IOException {
+        return getByte();
+    }
+
+
+    @Override
+    public int read(byte [] buffer, int offset, int length) throws IOException {
+        return getBytes(buffer, offset, length);
+    }
+
+    
+    @Override
+    public boolean markSupported() {
+        return false;
+    }
+
+
+    @Override
+    public int available() throws IOException {
+        return ((in.available() / 4) * 3) + decodedCount;
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/ContentDisposition.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/ContentDisposition.java
new file mode 100644
index 0000000000..f9d4524a00
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/ContentDisposition.java
@@ -0,0 +1,144 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.attachment;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ContentDisposition {
+    private static final String CD_HEADER_PARAMS_EXPRESSION =
+       "[\\w-]++( )?\\*?=( )?((\"[^\"]++\")|([^;]+))";
+    private static final Pattern CD_HEADER_PARAMS_PATTERN =
+            Pattern.compile(CD_HEADER_PARAMS_EXPRESSION);
+
+    private static final String CD_HEADER_EXT_PARAMS_EXPRESSION =
+            "(?i)(UTF-8|ISO-8859-1)''((?:%[0-9a-f]{2}|\\S)+)";
+    private static final Pattern CD_HEADER_EXT_PARAMS_PATTERN =
+            Pattern.compile(CD_HEADER_EXT_PARAMS_EXPRESSION);
+    private static final Pattern CODEPOINT_ENCODED_VALUE_PATTERN = Pattern.compile("&#[0-9]{4};|\\S");
+    
+    private static final String FILE_NAME = "filename";
+
+    private String value;
+    private String type;
+    private Map<String, String> params = new LinkedHashMap<>();
+
+    public ContentDisposition(String value) {
+        this.value = value;
+
+        String tempValue = value;
+
+        int index = tempValue.indexOf(';');
+        if (index > 0 && (tempValue.indexOf('=') >= index)) {
+            type = tempValue.substring(0, index).trim();
+            tempValue = tempValue.substring(index + 1);
+        }
+
+        String extendedFilename = null;
+        Matcher m = CD_HEADER_PARAMS_PATTERN.matcher(tempValue);
+        while (m.find()) {
+            final String paramName;
+            String paramValue = "";
+
+            String groupValue = m.group().trim();
+            int eqIndex = groupValue.indexOf('=');
+            if (eqIndex > 0) {
+                paramName = groupValue.substring(0, eqIndex).trim();
+                if (eqIndex + 1 != groupValue.length()) {
+                    paramValue = groupValue.substring(eqIndex + 1).trim().replace("\"", "");
+                }
+            } else {
+                paramName = groupValue;
+            }
+            // filename* looks like the only CD param that is human readable
+            // and worthy of the extended encoding support. Other parameters
+            // can be supported if needed, see the complete list below
+            /*
+                http://www.iana.org/assignments/cont-disp/cont-disp.xhtml#cont-disp-2
+
+                filename            name to be used when creating file [RFC2183]
+                creation-date       date when content was created [RFC2183]
+                modification-date   date when content was last modified [RFC2183]
+                read-date           date when content was last read [RFC2183]
+                size                approximate size of content in octets [RFC2183]
+                name                original field name in form [RFC2388]
+                voice               type or use of audio content [RFC2421]
+                handling            whether or not processing is required [RFC3204]
+             */
+            if ("filename*".equalsIgnoreCase(paramName)) {
+                // try to decode the value if it matches the spec
+                try {
+                    Matcher matcher = CD_HEADER_EXT_PARAMS_PATTERN.matcher(paramValue);
+                    if (matcher.matches()) {
+                        String encodingScheme = matcher.group(1);
+                        String encodedValue = matcher.group(2);
+                        paramValue = Rfc5987Util.decode(encodedValue, encodingScheme);
+                        extendedFilename = paramValue;
+                    }
+                } catch (UnsupportedEncodingException e) {
+                    // would be odd not to support UTF-8 or 8859-1
+                }
+            } else if (FILE_NAME.equalsIgnoreCase(paramName) && paramValue.contains("&#")) {
+                Matcher matcher = CODEPOINT_ENCODED_VALUE_PATTERN.matcher(paramValue);
+                StringBuilder sb = new StringBuilder();
+                while (matcher.find()) {
+                    String matched = matcher.group();
+                    if (matched.startsWith("&#")) {
+                        int codePoint = Integer.parseInt(matched.substring(2, 6));
+                        sb.append(Character.toChars(codePoint));
+                    } else {
+                        sb.append(matched.charAt(0));
+                    }
+                }
+                if (sb.length() > 0) {
+                    paramValue = sb.toString();
+                }
+            }
+            params.put(paramName.toLowerCase(), paramValue);
+        }
+        if (extendedFilename != null) {
+            params.put(FILE_NAME, extendedFilename);
+        }
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public String getFilename() {
+        return params.get(FILE_NAME);
+    }
+
+    public String getParameter(String name) {
+        return params.get(name);
+    }
+
+    public Map<String, String> getParameters() {
+        return Collections.unmodifiableMap(params);
+    }
+
+    public String toString() {
+        return value;
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/LazyAttachmentCollection.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/LazyAttachmentCollection.java
new file mode 100644
index 0000000000..339625bf18
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/LazyAttachmentCollection.java
@@ -0,0 +1,362 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.attachment;
+
+import java.io.IOException;
+import java.util.AbstractCollection;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import jakarta.activation.DataHandler;
+
+import org.apache.cxf.message.Attachment;
+
+public class LazyAttachmentCollection
+    implements Collection<Attachment> {
+
+    private AttachmentDeserializer deserializer;
+    private final List<Attachment> attachments = new ArrayList<>();
+    private final int maxAttachmentCount;
+
+    public LazyAttachmentCollection(AttachmentDeserializer deserializer, int maxAttachmentCount) {
+        super();
+        this.deserializer = deserializer;
+        this.maxAttachmentCount = maxAttachmentCount;
+    }
+
+    public List<Attachment> getLoadedAttachments() {
+        return attachments;
+    }
+
+    private void loadAll() {
+        try {
+            Attachment a = deserializer.readNext();
+            int count = 0;
+            while (a != null) {
+                attachments.add(a);
+                count++;
+                if (count > maxAttachmentCount) {
+                    throw new IOException("The message contains more attachments than are permitted");
+                }
+                a = deserializer.readNext();
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    /**
+     * Check for more attachments by attempting to deserialize the next attachment.
+     *
+     * @param shouldLoadNew if <i>false</i>, the "loaded attachments" List will not be changed.
+     * @return there is more attachment or not
+     * @throws IOException
+     */
+    public boolean hasNext(boolean shouldLoadNew) throws IOException {
+        if (shouldLoadNew) {
+            Attachment a = deserializer.readNext();
+            if (a != null) {
+                attachments.add(a);
+                return true;
+            }
+            return false;
+        }
+        return deserializer.hasNext();
+    }
+
+    public boolean hasNext() throws IOException {
+        return hasNext(true);
+    }
+    public Iterator<Attachment> iterator() {
+        return new Iterator<Attachment>() {
+            int current;
+            boolean removed;
+
+            public boolean hasNext() {
+                if (attachments.size() > current) {
+                    return true;
+                }
+
+                // check if there is another attachment
+                try {
+                    Attachment a = deserializer.readNext();
+                    if (a == null) {
+                        return false;
+                    }
+                    attachments.add(a);
+                    return true;
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+
+            @Override
+            public Attachment next() {
+                Attachment a = attachments.get(current);
+                current++;
+                removed = false;
+                return a;
+            }
+
+            @Override
+            public void remove() {
+                if (removed) {
+                    throw new IllegalStateException();
+                }
+                attachments.remove(--current);
+                removed = true;
+            }
+
+        };
+    }
+
+    public int size() {
+        loadAll();
+
+        return attachments.size();
+    }
+
+    public boolean add(Attachment arg0) {
+        return attachments.add(arg0);
+    }
+
+    public boolean addAll(Collection<? extends Attachment> arg0) {
+        return attachments.addAll(arg0);
+    }
+
+    public void clear() {
+        attachments.clear();
+    }
+
+    public boolean contains(Object arg0) {
+        return attachments.contains(arg0);
+    }
+
+    public boolean containsAll(Collection<?> arg0) {
+        return attachments.containsAll(arg0);
+    }
+
+    public boolean isEmpty() {
+        if (attachments.isEmpty()) {
+            return !iterator().hasNext();
+        }
+        return attachments.isEmpty();
+    }
+
+    public boolean remove(Object arg0) {
+        return attachments.remove(arg0);
+    }
+
+    public boolean removeAll(Collection<?> arg0) {
+        return attachments.removeAll(arg0);
+    }
+
+    public boolean retainAll(Collection<?> arg0) {
+        return attachments.retainAll(arg0);
+    }
+
+    public Object[] toArray() {
+        loadAll();
+
+        return attachments.toArray();
+    }
+
+    public <T> T[] toArray(T[] arg0) {
+        loadAll();
+
+        return attachments.toArray(arg0);
+    }
+
+    public Map<String, DataHandler> createDataHandlerMap() {
+        return new LazyAttachmentMap(this);
+    }
+
+    private static class LazyAttachmentMap implements Map<String, DataHandler> {
+        LazyAttachmentCollection collection;
+
+        LazyAttachmentMap(LazyAttachmentCollection c) {
+            collection = c;
+        }
+
+        public void clear() {
+            collection.clear();
+        }
+
+        public boolean containsKey(Object key) {
+            Iterator<Attachment> it = collection.iterator();
+            while (it.hasNext()) {
+                Attachment at = it.next();
+                if (key.equals(at.getId())) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public boolean containsValue(Object value) {
+            Iterator<Attachment> it = collection.iterator();
+            while (it.hasNext()) {
+                Attachment at = it.next();
+                if (value.equals(at.getDataHandler())) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public DataHandler get(Object key) {
+            Iterator<Attachment> it = collection.iterator();
+            while (it.hasNext()) {
+                Attachment at = it.next();
+                if (key.equals(at.getId())) {
+                    return at.getDataHandler();
+                }
+            }
+            return null;
+        }
+
+        public boolean isEmpty() {
+            return collection.isEmpty();
+        }
+        public int size() {
+            return collection.size();
+        }
+
+        public DataHandler remove(Object key) {
+            Iterator<Attachment> it = collection.iterator();
+            while (it.hasNext()) {
+                Attachment at = it.next();
+                if (key.equals(at.getId())) {
+                    collection.remove(at);
+                    return at.getDataHandler();
+                }
+            }
+            return null;
+        }
+        public DataHandler put(String key, DataHandler value) {
+            Attachment at = new AttachmentImpl(key, value);
+            collection.add(at);
+            return value;
+        }
+
+        public void putAll(Map<? extends String, ? extends DataHandler> t) {
+            for (Map.Entry<? extends String, ? extends DataHandler> ent : t.entrySet()) {
+                put(ent.getKey(), ent.getValue());
+            }
+        }
+
+
+        public Set<Map.Entry<String, DataHandler>> entrySet() {
+            return new AbstractSet<Map.Entry<String, DataHandler>>() {
+                public Iterator<Map.Entry<String, DataHandler>> iterator() {
+                    return new Iterator<Map.Entry<String, DataHandler>>() {
+                        Iterator<Attachment> it = collection.iterator();
+                        public boolean hasNext() {
+                            return it.hasNext();
+                        }
+                        public Map.Entry<String, DataHandler> next() {
+                            return new Map.Entry<String, DataHandler>() {
+                                Attachment at = it.next();
+                                public String getKey() {
+                                    return at.getId();
+                                }
+                                public DataHandler getValue() {
+                                    return at.getDataHandler();
+                                }
+                                public DataHandler setValue(DataHandler value) {
+                                    if (at instanceof AttachmentImpl) {
+                                        DataHandler h = at.getDataHandler();
+                                        ((AttachmentImpl)at).setDataHandler(value);
+                                        return h;
+                                    }
+                                    throw new UnsupportedOperationException();
+                                }
+                            };
+                        }
+                        @Override
+                        public void remove() {
+                            it.remove();
+                        }
+                    };
+                }
+                public int size() {
+                    return collection.size();
+                }
+            };
+        }
+
+        public Set<String> keySet() {
+            return new AbstractSet<String>() {
+                public Iterator<String> iterator() {
+                    return new Iterator<String>() {
+                        Iterator<Attachment> it = collection.iterator();
+                        public boolean hasNext() {
+                            return it.hasNext();
+                        }
+
+                        public String next() {
+                            return it.next().getId();
+                        }
+
+                        @Override
+                        public void remove() {
+                            it.remove();
+                        }
+                    };
+                }
+
+                public int size() {
+                    return collection.size();
+                }
+            };
+        }
+
+
+        public Collection<DataHandler> values() {
+            return new AbstractCollection<DataHandler>() {
+                public Iterator<DataHandler> iterator() {
+                    return new Iterator<DataHandler>() {
+                        Iterator<Attachment> it = collection.iterator();
+                        public boolean hasNext() {
+                            return it.hasNext();
+                        }
+                        public DataHandler next() {
+                            return it.next().getDataHandler();
+                        }
+                        @Override
+                        public void remove() {
+                            it.remove();
+                        }
+                    };
+                }
+
+                public int size() {
+                    return collection.size();
+                }
+            };
+        }
+
+    }
+
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/MimeBodyPartInputStream.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/MimeBodyPartInputStream.java
new file mode 100644
index 0000000000..ab80b89e8b
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/attachment/MimeBodyPartInputStream.java
@@ -0,0 +1,275 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.attachment;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+
+public class MimeBodyPartInputStream extends InputStream {
+
+    PushbackInputStream inStream;
+
+    boolean boundaryFound;
+    int pbAmount;
+    byte[] boundary;
+    byte[] boundaryBuffer;
+
+    private boolean closed;
+
+    public MimeBodyPartInputStream(PushbackInputStream inStreamParam,
+                                   byte[] boundaryParam,
+                                   int pbsize) {
+        super();
+        this.inStream = inStreamParam;
+        this.boundary = boundaryParam;
+        this.pbAmount = pbsize;
+    }
+
+    @Override
+    public int read(byte[] buf, int origOff, int origLen) throws IOException {
+        byte[] b = buf;
+        int off = origOff;
+        int len = origLen;
+        if (boundaryFound || closed) {
+            return -1;
+        }
+        if ((off < 0) || (off > b.length) || (len < 0)
+            || ((off + len) > b.length) || ((off + len) < 0)) {
+
+            throw new IndexOutOfBoundsException();
+        }
+        if (len == 0) {
+            return 0;
+        }
+        boolean bufferCreated = false;
+        if (len < boundary.length * 2) {
+            //buffer is too short to detect boundaries with it.  We'll need to create a larger buffer
+            bufferCreated = true;
+            if (boundaryBuffer == null) {
+                boundaryBuffer = new byte[boundary.length * 2];
+            }
+            b = boundaryBuffer;
+            off = 0;
+            len = boundaryBuffer.length;
+        }
+        if (len > pbAmount) {
+            len = pbAmount;  //can only pushback that much so make sure we can
+        }
+        int read = 0;
+        int idx = 0;
+        while (read >= 0 && idx < len && idx < (boundary.length * 2)) {
+            //make sure we read enough to detect the boundary
+            read = inStream.read(b, off + idx, len - idx);
+            if (read != -1) {
+                idx += read;
+            }
+        }
+        if (read == -1 && idx == 0) {
+            return -1;
+        }
+        len = idx;
+
+        int i = processBuffer(b, off, len);
+        if (bufferCreated && i > 0) {
+            // read more than we need, push it back
+            if (origLen >= i) {
+                System.arraycopy(b, 0, buf, origOff, i);
+            } else {
+                System.arraycopy(b, 0, buf, origOff, origLen);
+                inStream.unread(b, origLen, i - origLen);
+                i = origLen;
+            }
+        } else if (i == 0 && boundaryFound) {
+            return -1;
+        }
+
+        return i;
+    }
+
+    //Has Data after encountering CRLF
+    private boolean hasData(byte[] b, int initialPointer, int pointer, int off, int len)
+        throws IOException {
+        if (pointer < (off + len)) {
+            return true;
+        } else if (pointer >= 1000000000) {
+            inStream.unread(b, initialPointer, (off + len) - initialPointer);
+            return false;
+        } else {
+            int x = inStream.read();
+            if (x != -1) {
+                inStream.unread(x);
+                inStream.unread(b, initialPointer, (off + len) - initialPointer);
+                return false;
+            }
+            return true;
+        }
+    }
+
+    protected int processBuffer(byte[] buffer, int off, int len) throws IOException {
+        for (int i = off; i < (off + len); i++) {
+            boolean needUnread0d0a = false;
+            int value = buffer[i];
+            int initialI = i;
+            if (value == 13) {
+                if (!hasData(buffer, initialI, initialI + 1, off, len)) {
+                    return initialI - off;
+                }
+                value = buffer[initialI + 1];
+                if (value != 10) {
+                    continue;
+                }
+                if (!hasData(buffer, initialI, initialI + 2, off, len)) {
+                    return initialI - off;
+                }
+                value = buffer[initialI + 2];
+                if ((byte) value != boundary[0]) {
+                    i++;
+                    continue;
+                }
+                needUnread0d0a = true;
+                i += 2; //i after this points to boundary[0] element
+            } else if (value != boundary[0]) {
+                continue;
+            }
+
+            int boundaryIndex = 0;
+            while ((boundaryIndex < boundary.length) && (value == boundary[boundaryIndex])) {
+                if (!hasData(buffer, initialI, i + 1, off, len)) {
+                    return initialI - off;
+                }
+                value = buffer[++i];
+                boundaryIndex++;
+            }
+            if (boundaryIndex == boundary.length) {
+                // read the end of line character
+                if (initialI != off) {
+                    i = 1000000000;
+                }
+                if (initialI - off != 0
+                    && !hasData(buffer, initialI, i + 1, off, len)) {
+                    return initialI - off;
+                }
+                boundaryFound = true;
+                int j = i + 1;
+                if (j < len && buffer[j] == 45 && value == 45) {
+                    // Last mime boundary should have a succeeding "--"
+                    // as we are on it, read the terminating CRLF
+                    i += 2;
+                    //last mime boundary
+                }
+
+                //boundary matched (may or may not be last mime boundary)
+                int processed = initialI - off;
+                if ((len - ((i - off) + 2)) > 0) {
+                    inStream.unread(buffer, i + 2, len - (i + 2) + off);
+                }
+                return processed;
+            }
+
+            // Boundary not found. Restoring bytes skipped.
+            // write first skipped byte, push back the rest
+            if (value != -1) { //pushing back first byte of boundary
+                // Stream might have ended
+                i--;
+            }
+            if (needUnread0d0a) { //Pushing all,  returning 13
+                i = i - boundaryIndex;
+                i--; //for 10
+//                value = 13;
+            } else {
+                i = i - boundaryIndex;
+                i++;
+//                value = boundary[0];
+            }
+        }
+        return len;
+    }
+
+    public int read() throws IOException {
+        boolean needUnread0d0a = false;
+        if (boundaryFound) {
+            return -1;
+        }
+
+        // read the next value from stream
+        int value = inStream.read();
+        // A problem occurred because all the mime parts tends to have a /r/n
+        // at the end. Making it hard to transform them to correct
+        // DataSources.
+        // This logic introduced to handle it
+        if (value == 13) {
+            value = inStream.read();
+            if (value != 10) {
+                inStream.unread(value);
+                return 13;
+            }
+            value = inStream.read();
+            if ((byte) value != boundary[0]) {
+                inStream.unread(value);
+                inStream.unread(10);
+                return 13;
+            }
+            needUnread0d0a = true;
+        } else if ((byte) value != boundary[0]) {
+            return value;
+        }
+        // read value is the first byte of the boundary. Start matching the
+        // next characters to find a boundary
+        int boundaryIndex = 0;
+        while ((boundaryIndex < boundary.length) && ((byte) value == boundary[boundaryIndex])) {
+            value = inStream.read();
+            boundaryIndex++;
+        }
+        if (boundaryIndex == boundary.length) {
+            // boundary found
+            boundaryFound = true;
+            int dashNext = inStream.read();
+            // read the end of line character
+            if (dashNext == 45 && value == 45) {
+                // Last mime boundary should have a succeeding "--"
+                // as we are on it, read the terminating CRLF
+                inStream.read();
+                inStream.read();
+            }
+            return -1;
+        }
+        // Boundary not found. Restoring bytes skipped.
+        // write first skipped byte, push back the rest
+        if (value != -1) {
+            // Stream might have ended
+            inStream.unread(value);
+        }
+        if (needUnread0d0a) {
+            inStream.unread(boundary, 0, boundaryIndex);
+            inStream.unread(10);
+            value = 13;
+        } else {
+            inStream.unread(boundary, 1, boundaryIndex - 1);
+            value = boundary[0];
+        }
+        return value;
+    }
+
+    @Override
+    public void close() throws IOException {
+        this.closed = true;
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/CXFBusFactory.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/CXFBusFactory.java
new file mode 100644
index 0000000000..fb3a833002
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/CXFBusFactory.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.bus.extension.ExtensionManagerBus;
+
+public class CXFBusFactory extends BusFactory {
+
+    public Bus createBus() {
+        return createBus(new HashMap<>());
+    }
+
+    public Bus createBus(Map<Class<?>, Object> e) {
+        return createBus(e, new HashMap<>());
+    }
+
+    public Bus createBus(Map<Class<?>, Object> e, Map<String, Object> properties) {
+        ExtensionManagerBus bus = new ExtensionManagerBus(e, properties);
+        possiblySetDefaultBus(bus);
+        initializeBus(bus);
+        bus.initialize();
+        return bus;
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/blueprint/BundleDelegatingClassLoader.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/blueprint/BundleDelegatingClassLoader.java
new file mode 100644
index 0000000000..ff957c2545
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/blueprint/BundleDelegatingClassLoader.java
@@ -0,0 +1,134 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus.blueprint;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * A ClassLoader delegating to a given OSGi bundle.
+ */
+public class BundleDelegatingClassLoader extends ClassLoader {
+
+    private final Bundle bundle;
+    private final ClassLoader classLoader;
+
+    public BundleDelegatingClassLoader(Bundle bundle) {
+        this(bundle, null);
+    }
+
+    public BundleDelegatingClassLoader(Bundle bundle, ClassLoader classLoader) {
+        this.bundle = bundle;
+        this.classLoader = classLoader;
+    }
+
+    @Override
+    protected Class<?> findClass(final String name) throws ClassNotFoundException {
+        try {
+            return AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>() {
+                public Class<?> run() throws ClassNotFoundException {
+                    return bundle.loadClass(name);
+                }
+            });
+        } catch (PrivilegedActionException e) {
+            Exception cause = e.getException();
+
+            if (cause instanceof ClassNotFoundException) {
+                throw (ClassNotFoundException)cause;
+            }
+            throw (RuntimeException)cause;
+        }
+    }
+
+    @Override
+    protected URL findResource(final String name) {
+        URL resource = AccessController.doPrivileged(new PrivilegedAction<URL>() {
+            public URL run() {
+                return bundle.getResource(name);
+            }
+        });
+        if (classLoader != null && resource == null) {
+            resource = classLoader.getResource(name);
+        }
+        return resource;
+    }
+
+    @Override
+    protected Enumeration<URL> findResources(final String name) throws IOException {
+        Enumeration<URL> urls;
+        try {
+            urls = AccessController.doPrivileged(new PrivilegedExceptionAction<Enumeration<URL>>() {
+                public Enumeration<URL> run() throws IOException {
+                    return bundle.getResources(name);
+                }
+
+            });
+        } catch (PrivilegedActionException e) {
+            Exception cause = e.getException();
+
+            if (cause instanceof IOException) {
+                throw (IOException)cause;
+            }
+            throw (RuntimeException)cause;
+        }
+
+        if (urls == null) {
+            urls = Collections.enumeration(new ArrayList<>());
+        }
+
+        return urls;
+    }
+
+    @Override
+    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+        Class<?> clazz;
+        try {
+            clazz = findClass(name);
+        } catch (ClassNotFoundException cnfe) {
+            if (classLoader != null) {
+                try {
+                    clazz = classLoader.loadClass(name);
+                } catch (ClassNotFoundException e) {
+                    throw new ClassNotFoundException(name + " from bundle " + bundle.getBundleId()
+                                                     + " (" + bundle.getSymbolicName() + ")", cnfe);
+                }
+            } else {
+                throw new ClassNotFoundException(name + " from bundle " + bundle.getBundleId()
+                                                 + " (" + bundle.getSymbolicName() + ")", cnfe);
+            }
+        }
+        if (resolve) {
+            resolveClass(clazz);
+        }
+        return clazz;
+    }
+
+    public Bundle getBundle() {
+        return bundle;
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/blueprint/BusDefinitionParser.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/blueprint/BusDefinitionParser.java
new file mode 100644
index 0000000000..baf83b7671
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/blueprint/BusDefinitionParser.java
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus.blueprint;
+
+
+import org.w3c.dom.Element;
+
+import org.apache.aries.blueprint.ParserContext;
+import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.configuration.blueprint.AbstractBPBeanDefinitionParser;
+import org.osgi.service.blueprint.reflect.Metadata;
+
+public class BusDefinitionParser
+    extends AbstractBPBeanDefinitionParser {
+
+    public BusDefinitionParser() {
+    }
+
+    public Metadata parse(Element element, ParserContext context) {
+        String bname = element.hasAttribute("bus") ? element.getAttribute("bus") : "cxf";
+        String id = element.hasAttribute("id") ? element.getAttribute("id") : null;
+        MutableBeanMetadata cxfBean = getBus(context, bname);
+        parseAttributes(element, context, cxfBean);
+        parseChildElements(element, context, cxfBean);
+        context.getComponentDefinitionRegistry().removeComponentDefinition(bname);
+        if (!StringUtils.isEmpty(id)) {
+            cxfBean.addProperty("id", createValue(context, id));
+        }
+        return cxfBean;
+    }
+    
+    @Override
+    protected void processBusAttribute(Element element, ParserContext ctx,
+                                       MutableBeanMetadata bean, String val) {
+        //nothing
+    }
+    
+    @Override
+    protected boolean hasBusProperty() {
+        return false;
+    }
+
+
+    @Override
+    protected void mapElement(ParserContext ctx, MutableBeanMetadata bean, Element el, String name) {
+        if ("inInterceptors".equals(name) || "inFaultInterceptors".equals(name)
+            || "outInterceptors".equals(name) || "outFaultInterceptors".equals(name)
+            || "features".equals(name)) {
+            bean.addProperty(name, parseListData(ctx, bean, el));
+        } else if ("properties".equals(name)) {
+            bean.addProperty(name, parseMapData(ctx, bean, el));
+        }
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/blueprint/ConfigurerImpl.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/blueprint/ConfigurerImpl.java
new file mode 100644
index 0000000000..37f82fedaa
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/blueprint/ConfigurerImpl.java
@@ -0,0 +1,180 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus.blueprint;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.aries.blueprint.services.ExtendedBlueprintContainer;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.configuration.Configurable;
+import org.apache.cxf.configuration.Configurer;
+import org.osgi.service.blueprint.container.BlueprintContainer;
+import org.osgi.service.blueprint.container.NoSuchComponentException;
+import org.osgi.service.blueprint.reflect.BeanMetadata;
+import org.osgi.service.blueprint.reflect.ComponentMetadata;
+
+/**
+ *
+ */
+public class ConfigurerImpl implements Configurer {
+    private static final Logger LOG = LogUtils.getL7dLogger(ConfigurerImpl.class);
+    BlueprintContainer container;
+
+    private final Map<String, List<MatcherHolder>> wildCardBeanDefinitions
+        = new TreeMap<>();
+
+    static class MatcherHolder implements Comparable<MatcherHolder> {
+        Matcher matcher;
+        String wildCardId;
+        MatcherHolder(String orig, Matcher matcher) {
+            wildCardId = orig;
+            this.matcher = matcher;
+        }
+        @Override
+        public int compareTo(MatcherHolder mh) {
+            int literalCharsLen1 = this.wildCardId.replace("*", "").length();
+            int literalCharsLen2 = mh.wildCardId.replace("*", "").length();
+            // The expression with more literal characters should end up on the top of the list
+            return Integer.compare(literalCharsLen1, literalCharsLen2) * -1;
+        }
+    }
+
+    public ConfigurerImpl(BlueprintContainer con) {
+        container = con;
+        initializeWildcardMap();
+    }
+    private boolean isWildcardBeanName(String bn) {
+        return bn.indexOf('*') != -1 || bn.indexOf('?') != -1
+            || (bn.indexOf('(') != -1 && bn.indexOf(')') != -1);
+    }
+
+    private void initializeWildcardMap() {
+        for (String s : container.getComponentIds()) {
+            if (isWildcardBeanName(s)) {
+                ComponentMetadata cmd = container.getComponentMetadata(s);
+                Class<?> cls = BlueprintBeanLocator.getClassForMetaData(container, cmd);
+                if (cls != null) {
+                    final String cid = s.charAt(0) != '*' ? s
+                            : "." + s.replaceAll("\\.", "\\."); //old wildcard
+                    Matcher matcher = Pattern.compile(cid).matcher("");
+                    List<MatcherHolder> m = wildCardBeanDefinitions.get(cls.getName());
+                    if (m == null) {
+                        m = new ArrayList<>();
+                        wildCardBeanDefinitions.put(cls.getName(), m);
+                    }
+                    MatcherHolder holder = new MatcherHolder(s, matcher);
+                    m.add(holder);
+                }
+            }
+        }
+    }
+
+    public void configureBean(Object beanInstance) {
+        configureBean(null, beanInstance, true);
+    }
+
+    public void configureBean(String bn, Object beanInstance) {
+        configureBean(bn, beanInstance, true);
+    }
+    public synchronized void configureBean(String bn, Object beanInstance, boolean checkWildcards) {
+        if (null == bn) {
+            bn = getBeanName(beanInstance);
+        }
+
+        if (null == bn) {
+            return;
+        }
+        if (checkWildcards) {
+            configureWithWildCard(bn, beanInstance);
+        }
+
+        if (container instanceof ExtendedBlueprintContainer) {
+            try {
+                final ComponentMetadata cm = container.getComponentMetadata(bn);
+                if (cm instanceof BeanMetadata) {
+                    ((ExtendedBlueprintContainer)container).injectBeanInstance((BeanMetadata)cm, beanInstance);
+                }
+            } catch (NoSuchComponentException nsce) {
+            }
+        }
+    }
+
+    private void configureWithWildCard(String bn, Object beanInstance) {
+        if (!wildCardBeanDefinitions.isEmpty()) {
+            Class<?> clazz = beanInstance.getClass();
+            while (!Object.class.equals(clazz)) {
+                String className = clazz.getName();
+                List<MatcherHolder> matchers = wildCardBeanDefinitions.get(className);
+                if (matchers != null) {
+                    for (MatcherHolder m : matchers) {
+                        synchronized (m.matcher) {
+                            m.matcher.reset(bn);
+                            if (m.matcher.matches()) {
+                                configureBean(m.wildCardId, beanInstance, false);
+                                return;
+                            }
+                        }
+                    }
+                }
+                clazz = clazz.getSuperclass();
+            }
+        }
+    }
+
+    protected String getBeanName(Object beanInstance) {
+        if (beanInstance instanceof Configurable) {
+            return ((Configurable)beanInstance).getBeanName();
+        }
+        String beanName = null;
+        Method m = null;
+        try {
+            m = beanInstance.getClass().getDeclaredMethod("getBeanName", (Class[])null);
+        } catch (NoSuchMethodException ex) {
+            try {
+                m = beanInstance.getClass().getMethod("getBeanName", (Class[])null);
+            } catch (NoSuchMethodException e) {
+                //ignore
+            }
+        }
+        if (m != null) {
+            try {
+                beanName = (String)(m.invoke(beanInstance));
+            } catch (Exception ex) {
+                LogUtils.log(LOG, Level.WARNING, "ERROR_DETERMINING_BEAN_NAME_EXC", ex);
+            }
+        }
+
+        if (null == beanName) {
+            LogUtils.log(LOG, Level.FINE, "COULD_NOT_DETERMINE_BEAN_NAME_MSG",
+                         beanInstance.getClass().getName());
+        }
+
+        return beanName;
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/extension/Extension.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/extension/Extension.java
new file mode 100644
index 0000000000..03f0dc6192
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/extension/Extension.java
@@ -0,0 +1,291 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus.extension;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.i18n.Message;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.StringUtils;
+
+public class Extension {
+    protected static final Logger LOG = LogUtils.getL7dLogger(Extension.class);
+    
+    private static final String PROBLEM_CREATING_EXTENSION_CLASS = "PROBLEM_CREATING_EXTENSION_CLASS";
+
+    protected String className;
+    protected ClassLoader classloader;
+    protected volatile Class<?> clazz;
+    protected volatile Class<?> intf;
+    protected String interfaceName;
+    protected boolean deferred;
+    protected Collection<String> namespaces = new ArrayList<>();
+    protected Object[] args;
+    protected volatile Object obj;
+    protected boolean optional;
+    protected boolean notFound;
+    
+
+    public Extension() {
+    }
+
+    public Extension(Class<?> cls, Class<?> inf) {
+        clazz = cls;
+        intf = inf;
+        interfaceName = inf.getName();
+        className = cls.getName();
+        classloader = cls.getClassLoader();
+    }
+    public Extension(Class<?> cls) {
+        clazz = cls;
+        className = cls.getName();
+        classloader = cls.getClassLoader();
+    }
+    public Extension(ClassLoader loader) {
+        classloader = loader;
+    }
+
+    public Extension(Extension ext) {
+        className = ext.className;
+        interfaceName = ext.interfaceName;
+        deferred = ext.deferred;
+        namespaces = ext.namespaces;
+        obj = ext.obj;
+        clazz = ext.clazz;
+        intf = ext.intf;
+        classloader = ext.classloader;
+        args = ext.args;
+        optional = ext.optional;
+    }
+
+    public void setOptional(boolean b) {
+        optional = b;
+    }
+    public boolean isOptional() {
+        return optional;
+    }
+
+    public String getName() {
+        return StringUtils.isEmpty(interfaceName) ? className : interfaceName;
+    }
+    public Object getLoadedObject() {
+        return obj;
+    }
+
+    public Extension cloneNoObject() {
+        Extension ext = new Extension(this);
+        ext.obj = null;
+        ext.clazz = null;
+        ext.intf = null;
+        return ext;
+    }
+
+    public String toString() {
+        StringBuilder buf = new StringBuilder(128);
+        buf.append("class: ");
+        buf.append(className);
+        buf.append(", interface: ");
+        buf.append(interfaceName);
+        buf.append(", deferred: ");
+        buf.append(deferred ? "true" : "false");
+        buf.append(", namespaces: (");
+        int n = 0;
+        for (String ns : namespaces) {
+            if (n > 0) {
+                buf.append(", ");
+            }
+            buf.append(ns);
+            n++;
+        }
+        buf.append(')');
+        return buf.toString();
+    }
+
+    public String getClassname() {
+        return className;
+    }
+
+    public void setClassname(String i) {
+        clazz = null;
+        notFound = false;
+        className = i;
+    }
+
+    public String getInterfaceName() {
+        return interfaceName;
+    }
+
+    public void setInterfaceName(String i) {
+        interfaceName = i;
+        notFound = false;
+    }
+
+    public boolean isDeferred() {
+        return deferred;
+    }
+
+    public void setDeferred(boolean d) {
+        deferred = d;
+    }
+
+    public Collection<String> getNamespaces() {
+        return namespaces;
+    }
+
+    public void setArgs(Object[] a) {
+        args = a;
+    }
+
+    protected Class<?> tryClass(String name, ClassLoader cl) {
+        Throwable origEx = null;
+        if (classloader != null) {
+            try {
+                return classloader.loadClass(name);
+            } catch (Throwable nex) {
+                //ignore, fall into the stuff below
+                //save the exception though as this is likely the important one
+                origEx = nex;
+            }
+        }
+        try {
+            return cl.loadClass(name);
+        } catch (Throwable ex) {
+            try {
+                // using the extension classloader as a fallback
+                return this.getClass().getClassLoader().loadClass(name);
+            } catch (Throwable nex) {
+                notFound = true;
+                if (!optional) {
+                    throw new ExtensionException(new Message("PROBLEM_LOADING_EXTENSION_CLASS", LOG, name),
+                        origEx != null ? origEx : ex);
+                }
+            }
+        }
+        return null;
+    }
+
+    public Class<?> getClassObject(ClassLoader cl) {
+        if (notFound) {
+            return null;
+        }
+        if (clazz != null) {
+            return clazz;
+        }
+        synchronized (this) {
+            if (clazz == null) {
+                clazz = tryClass(className, cl);
+            }
+        }
+        return clazz;
+    }
+    public Object load(ClassLoader cl, Bus b) {
+        if (obj != null) {
+            return obj;
+        }
+        Class<?> cls = getClassObject(cl);
+        try {
+            if (notFound) {
+                return null;
+            }
+            try {
+                //if there is a Bus constructor, use it.
+                if (b != null && args == null) {
+                    Constructor<?> con = cls.getConstructor(Bus.class);
+                    obj = con.newInstance(b);
+                    return obj;
+                } else if (b != null && args != null) {
+                    try {
+                        obj = cls.getConstructor(Bus.class, Object[].class).newInstance(b, args);
+                    } catch (NoSuchMethodException ex) { // no bus
+                        obj = cls.getConstructor(Object[].class).newInstance(args);
+                    }
+                    return obj;
+                } else if (args != null) {
+                    Constructor<?> con = cls.getConstructor(Object[].class);
+                    obj = con.newInstance(args);
+                    return obj;
+                }
+            } catch (InvocationTargetException ex) {
+                throw new ExtensionException(new Message(PROBLEM_CREATING_EXTENSION_CLASS, LOG, cls.getName()),
+                                             ex.getCause());
+            } catch (InstantiationException | SecurityException ex) {
+                throw new ExtensionException(new Message(PROBLEM_CREATING_EXTENSION_CLASS, LOG, cls.getName()), ex);
+            } catch (NoSuchMethodException e) {
+                //ignore
+            }
+            obj = cls.getConstructor().newInstance();
+        } catch (ExtensionException ex) {
+            notFound = true;
+            if (!optional) {
+                throw ex;
+            }
+            LOG.log(Level.FINE, "Could not load optional extension " + getName(), ex);
+        } catch (InvocationTargetException ex) {
+            notFound = true;
+            if (!optional) {
+                throw new ExtensionException(new Message(PROBLEM_CREATING_EXTENSION_CLASS, LOG, cls.getName()),
+                                             ex.getCause());
+            }
+            LOG.log(Level.FINE, "Could not load optional extension " + getName(), ex);
+        } catch (NoSuchMethodException ex) {
+            notFound = true;
+            List<Object> a = new ArrayList<>();
+            if (b != null) {
+                a.add(b);
+            }
+            if (args != null) {
+                a.add(args);
+            }
+            if (!optional) {
+                throw new ExtensionException(new Message("PROBLEM_FINDING_CONSTRUCTOR", LOG,
+                                                         cls.getName(), a), ex);
+            }
+            LOG.log(Level.FINE, "Could not load optional extension " + getName(), ex);
+        } catch (Throwable e) {
+            notFound = true;
+            if (!optional) {
+                throw new ExtensionException(new Message(PROBLEM_CREATING_EXTENSION_CLASS, LOG, cls.getName()), e);
+            }
+            LOG.log(Level.FINE, "Could not load optional extension " + getName(), e);
+        }
+        return obj;
+    }
+
+    public Class<?> loadInterface(ClassLoader cl) {
+        if (intf != null || notFound) {
+            return intf;
+        }
+        synchronized (this) {
+            if (intf == null) {
+                intf = tryClass(interfaceName, cl);
+            }
+        }
+        return intf;
+    }
+
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/extension/ExtensionManagerImpl.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/extension/ExtensionManagerImpl.java
new file mode 100644
index 0000000000..d4ce0be177
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/extension/ExtensionManagerImpl.java
@@ -0,0 +1,381 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus.extension;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.injection.ResourceInjector;
+import org.apache.cxf.configuration.ConfiguredBeanLocator;
+import org.apache.cxf.configuration.Configurer;
+import org.apache.cxf.resource.ObjectTypeResolver;
+import org.apache.cxf.resource.ResourceManager;
+import org.apache.cxf.resource.ResourceResolver;
+import org.apache.cxf.resource.SinglePropertyResolver;
+
+public class ExtensionManagerImpl implements ExtensionManager, ConfiguredBeanLocator {
+    public static final String EXTENSIONMANAGER_PROPERTY_NAME = "extensionManager";
+    public static final String ACTIVATION_NAMESPACES_PROPERTY_NAME = "activationNamespaces";
+    public static final String ACTIVATION_NAMESPACES_SETTER_METHOD_NAME = "setActivationNamespaces";
+    public static final String BUS_EXTENSION_RESOURCE = "META-INF/cxf/bus-extensions.txt";
+
+    private final ClassLoader loader;
+    private ResourceManager resourceManager;
+    private Map<String, Extension> all = new ConcurrentHashMap<>();
+    private List<Extension> ordered = new CopyOnWriteArrayList<>();
+    private final Map<Class<?>, Object> activated;
+    private final Bus bus;
+
+    public ExtensionManagerImpl(ClassLoader cl, Map<Class<?>, Object> initialExtensions,
+                                ResourceManager rm, Bus b) {
+        this(new String[] {BUS_EXTENSION_RESOURCE},
+                 cl, initialExtensions, rm, b);
+    }
+    public ExtensionManagerImpl(String resource,
+                                ClassLoader cl,
+                                Map<Class<?>, Object> initialExtensions,
+                                ResourceManager rm,
+                                Bus b) {
+        this(new String[] {resource}, cl, initialExtensions, rm, b);
+    }
+    public ExtensionManagerImpl(String[] resources,
+                                ClassLoader cl,
+                                Map<Class<?>, Object> initialExtensions,
+                                ResourceManager rm,
+                                Bus b) {
+
+        loader = cl;
+        bus = b;
+        activated = initialExtensions;
+        resourceManager = rm;
+
+        ResourceResolver extensionManagerResolver =
+            new SinglePropertyResolver(EXTENSIONMANAGER_PROPERTY_NAME, this);
+        resourceManager.addResourceResolver(extensionManagerResolver);
+        resourceManager.addResourceResolver(new ObjectTypeResolver(this));
+
+        load(resources);
+        for (Map.Entry<String, Extension> ext : ExtensionRegistry.getRegisteredExtensions().entrySet()) {
+            if (!all.containsKey(ext.getKey())) {
+                all.put(ext.getKey(), ext.getValue());
+                ordered.add(ext.getValue());
+            }
+        }
+    }
+
+    final void load(String[] resources) {
+        if (resources == null) {
+            return;
+        }
+        try {
+            for (String resource : resources) {
+                load(resource);
+            }
+        } catch (IOException ex) {
+            throw new ExtensionException(ex);
+        }
+    }
+    public void add(Extension ex) {
+        all.put(ex.getName(), ex);
+        ordered.add(ex);
+    }
+
+    public void initialize() {
+        for (Extension e : ordered) {
+            if (!e.isDeferred() && e.getLoadedObject() == null) {
+                loadAndRegister(e);
+            }
+        }
+    }
+
+    public void removeBeansOfNames(List<String> names) {
+        for (String s : names) {
+            Extension ex = all.remove(s);
+            if (ex != null) {
+                ordered.remove(ex);
+            }
+        }
+    }
+    public void activateAll() {
+        for (Extension e : ordered) {
+            if (e.getLoadedObject() == null) {
+                loadAndRegister(e);
+            }
+        }
+    }
+    public <T> void activateAllByType(Class<T> type) {
+        for (Extension e : ordered) {
+            if (e.getLoadedObject() == null) {
+                Class<?> cls = e.getClassObject(loader);
+                if (cls != null && type.isAssignableFrom(cls)) {
+                    synchronized (e) {
+                        loadAndRegister(e);
+                    }
+                }
+            }
+        }
+    }
+
+    public boolean hasBeanOfName(String name) {
+        return all.containsKey(name);
+    }
+
+    final void load(String resource) throws IOException {
+        if (loader != getClass().getClassLoader()) {
+            load(resource, getClass().getClassLoader());
+        }
+        load(resource, loader);
+    }
+    final synchronized void load(String resource, ClassLoader l) throws IOException {
+
+        Enumeration<URL> urls = l.getResources(resource);
+
+        while (urls.hasMoreElements()) {
+            final URL url = urls.nextElement();
+            try (InputStream is = AccessController.doPrivileged(new PrivilegedExceptionAction<InputStream>() {
+                    public InputStream run() throws Exception {
+                        return url.openStream();
+                    }
+                })) {
+                List<Extension> exts = new TextExtensionFragmentParser(loader).getExtensions(is);
+                for (Extension e : exts) {
+                    if (loader != l) {
+                        e.classloader = l;
+                    }
+                    if (!all.containsKey(e.getName())) {
+                        all.put(e.getName(), e);
+                        ordered.add(e);
+                    }
+                }
+            } catch (PrivilegedActionException pae) {
+                throw (IOException)pae.getException();
+            }
+        }
+    }
+
+    final void loadAndRegister(Extension e) {
+        Class<?> cls;
+        if (null != e.getInterfaceName() && !"".equals(e.getInterfaceName())) {
+            cls = e.loadInterface(loader);
+        }  else {
+            cls = e.getClassObject(loader);
+        }
+        if (null != activated && null != cls && null != activated.get(cls)) {
+            return;
+        }
+
+        synchronized (e) {
+            Object obj = e.load(loader, bus);
+            if (obj == null) {
+                return;
+            }
+
+            if (null != activated) {
+                Configurer configurer = (Configurer)(activated.get(Configurer.class));
+                if (null != configurer) {
+                    configurer.configureBean(obj);
+                }
+            }
+
+            // let the object know for which namespaces it has been activated
+            ResourceResolver namespacesResolver = null;
+            if (null != e.getNamespaces()) {
+                namespacesResolver = new SinglePropertyResolver(ACTIVATION_NAMESPACES_PROPERTY_NAME,
+                                                                e.getNamespaces());
+                resourceManager.addResourceResolver(namespacesResolver);
+            }
+
+            // Since we need to support spring2.5 by removing @Resource("activationNamespaces")
+            // Now we call the setActivationNamespaces method directly here
+            if (e.getNamespaces() != null && !e.getNamespaces().isEmpty()) {
+                invokeSetterActivationNSMethod(obj, e.getNamespaces());
+            }
+
+            ResourceInjector injector = new ResourceInjector(resourceManager);
+
+            try {
+                injector.inject(obj);
+                injector.construct(obj);
+            } finally {
+                if (null != namespacesResolver) {
+                    resourceManager.removeResourceResolver(namespacesResolver);
+                }
+            }
+
+            if (null != activated) {
+                if (cls == null) {
+                    cls = obj.getClass();
+                }
+                activated.put(cls, obj);
+            }
+        }
+    }
+
+    public <T> T getExtension(String name, Class<T> type) {
+        if (name == null) {
+            return null;
+        }
+        Extension e = all.get(name);
+        if (e != null) {
+            Class<?> cls = e.getClassObject(loader);
+            if (cls != null && type.isAssignableFrom(cls)) {
+                synchronized (e) {
+                    if (e.getLoadedObject() == null) {
+                        loadAndRegister(e);
+                    }
+                    return type.cast(e.getLoadedObject());
+                }
+            }
+        }
+        return null;
+    }
+
+    private void invokeSetterActivationNSMethod(Object target, Object value) {
+        Class<?> clazz = target.getClass();
+        String methodName = ACTIVATION_NAMESPACES_SETTER_METHOD_NAME;
+        while (clazz != Object.class) {
+            Method[] methods = clazz.getMethods();
+            for (int i = 0; i < methods.length; i++) {
+                Method method = methods[i];
+                Class<?>[] params = method.getParameterTypes();
+                if (method.getName().equals(methodName) && params.length == 1) {
+                    Class<?> paramType = params[0];
+                    if (paramType.isInstance(value)) {
+                        try {
+                            method.invoke(target, new Object[] {value});
+                        } catch (Exception e) {
+                            // do nothing here
+                        }
+                        return;
+                    }
+                }
+            }
+            clazz = clazz.getSuperclass();
+        }
+    }
+    public List<String> getBeanNamesOfType(Class<?> type) {
+        List<String> ret = new LinkedList<>();
+        for (Extension ex : ordered) {
+            Class<?> cls = ex.getClassObject(loader);
+            if (cls != null && type.isAssignableFrom(cls)) {
+                synchronized (ex) {
+                    ret.add(ex.getName());
+                }
+            }
+        }
+        return ret;
+    }
+    public <T> T getBeanOfType(String name, Class<T> type) {
+        if (name == null) {
+            return null;
+        }
+        Extension ex = all.get(name);
+        if (ex != null) {
+            if (ex.getLoadedObject() == null) {
+                loadAndRegister(ex);
+            }
+            return type.cast(ex.getLoadedObject());
+        }
+        return null;
+    }
+    public <T> Collection<? extends T> getBeansOfType(Class<T> type) {
+        List<T> ret = new LinkedList<>();
+        Extension ext = all.get(type.getName());
+        if (ext != null) {
+            Class<?> cls = ext.getClassObject(loader);
+            if (cls != null && type.isAssignableFrom(cls)) {
+                synchronized (ext) {
+                    if (ext.getLoadedObject() == null) {
+                        loadAndRegister(ext);
+                    }
+                    if (ext.getLoadedObject() != null) {
+                        ret.add(type.cast(ext.getLoadedObject()));
+                    }
+                }
+            }
+        }
+        for (Extension ex : ordered) {
+            if (ex != ext) {
+                Class<?> cls = ex.getClassObject(loader);
+                if (cls != null && type.isAssignableFrom(cls)) {
+                    synchronized (ex) {
+                        if (ex.getLoadedObject() == null) {
+                            loadAndRegister(ex);
+                        }
+                        if (ex.getLoadedObject() != null) {
+                            ret.add(type.cast(ex.getLoadedObject()));
+                        }
+                    }
+                }
+            }
+        }
+        return ret;
+    }
+    public <T> boolean loadBeansOfType(Class<T> type, BeanLoaderListener<T> listener) {
+        boolean loaded = false;
+        for (Extension ex : ordered) {
+            Class<?> cls = ex.getClassObject(loader);
+            if (cls != null
+                && type.isAssignableFrom(cls)) {
+                synchronized (ex) {
+                    if (listener.loadBean(ex.getName(), cls.asSubclass(type))) {
+                        if (ex.getLoadedObject() == null) {
+                            loadAndRegister(ex);
+                        }
+                        if (listener.beanLoaded(ex.getName(), type.cast(ex.getLoadedObject()))) {
+                            return true;
+                        }
+                        loaded = true;
+                    }
+                }
+            }
+        }
+        return loaded;
+    }
+    public boolean hasConfiguredPropertyValue(String beanName, String propertyName, String value) {
+        if (beanName == null) {
+            return false;
+        }
+        Extension ex = all.get(beanName);
+        return ex != null && ex.getNamespaces() != null
+            && ex.getNamespaces().contains(value);
+    }
+    public void destroyBeans() {
+        for (Extension ex : ordered) {
+            if (ex.getLoadedObject() != null) {
+                ResourceInjector injector = new ResourceInjector(resourceManager);
+                injector.destroy(ex.getLoadedObject());
+            }
+        }
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/managers/ServiceContractResolverRegistryImpl.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/managers/ServiceContractResolverRegistryImpl.java
new file mode 100644
index 0000000000..a0f7af0c8e
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/managers/ServiceContractResolverRegistryImpl.java
@@ -0,0 +1,113 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus.managers;
+
+import java.net.URI;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.xml.namespace.QName;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.injection.NoJSR250Annotations;
+import org.apache.cxf.endpoint.ServiceContractResolver;
+import org.apache.cxf.endpoint.ServiceContractResolverRegistry;
+
+/**
+ * A simple contract resolver registry. It maintains a list of contract resolvers in an
+ * <code>ArrayList</code>.
+ */
+@NoJSR250Annotations(unlessNull = "bus")
+public class ServiceContractResolverRegistryImpl implements ServiceContractResolverRegistry {
+
+    private List<ServiceContractResolver> resolvers
+        = new CopyOnWriteArrayList<>();
+
+    public ServiceContractResolverRegistryImpl() {
+
+    }
+    public ServiceContractResolverRegistryImpl(Bus b) {
+        setBus(b);
+    }
+
+
+    /**
+     * Sets the bus with which the registry is associated.
+     *
+     * @param bus
+     */
+    public final void setBus(Bus bus) {
+        if (bus != null) {
+            bus.setExtension(this, ServiceContractResolverRegistry.class);
+        }
+    }
+
+    /**
+     * Calls each of the registered <code>ServiceContractResolver</code> instances
+     * to resolve the location of the service's contract. It returns the location
+     * from the first resolver that matches the QName to a location.
+     *
+     * @param qname QName to be resolved into a contract location
+     * @return URI representing the location of the contract
+    */
+    public URI getContractLocation(QName qname) {
+        for (ServiceContractResolver resolver : resolvers) {
+            URI contractLocation = resolver.getContractLocation(qname);
+            if (null != contractLocation) {
+                return contractLocation;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Tests if a resolver is alreadey registered with this registry.
+     *
+     * @param resolver the contract resolver for which to searche
+     * @return <code>true</code> if the resolver is registered
+     */
+    public boolean isRegistered(ServiceContractResolver resolver) {
+        return resolvers.contains(resolver);
+    }
+
+    /**
+     * Registers a contract resolver with this registry.
+     *
+     * @param resolver the contract resolver to register
+     */
+    public synchronized void register(ServiceContractResolver resolver) {
+        resolvers.add(resolver);
+    }
+
+    /**
+     * Removes a contract resolver from this registry.
+     *
+     * @param resolver the contract resolver to remove
+     */
+    public synchronized void unregister(ServiceContractResolver resolver) {
+        resolvers.remove(resolver);
+    }
+
+
+    protected List<ServiceContractResolver> getResolvers() {
+        return resolvers;
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/osgi/CXFActivator.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/osgi/CXFActivator.java
new file mode 100644
index 0000000000..65042764a3
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/osgi/CXFActivator.java
@@ -0,0 +1,134 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus.osgi;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cxf.bus.blueprint.BlueprintNameSpaceHandlerFactory;
+import org.apache.cxf.bus.blueprint.NamespaceHandlerRegisterer;
+import org.apache.cxf.bus.extension.Extension;
+import org.apache.cxf.bus.extension.ExtensionRegistry;
+import org.apache.cxf.common.util.CollectionUtils;
+import org.apache.cxf.internal.CXFAPINamespaceHandler;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Is called in OSGi on start and stop of the cxf bundle.
+ * Manages
+ * - CXFBundleListener
+ * - Attaching ManagedWorkqueues to config admin service
+ * - OsgiBusListener
+ * - Blueprint namespaces
+ */
+public class CXFActivator implements BundleActivator {
+
+    private List<Extension> extensions;
+    private ManagedWorkQueueList workQueues;
+    private ServiceTracker<ConfigurationAdmin, ConfigurationAdmin> configAdminTracker;
+    private CXFExtensionBundleListener cxfBundleListener;
+    private ServiceRegistration<ManagedServiceFactory> workQueueServiceRegistration;
+
+
+
+    /** {@inheritDoc}*/
+    public void start(BundleContext context) throws Exception {
+        workQueues = new ManagedWorkQueueList();
+        cxfBundleListener = new CXFExtensionBundleListener(context.getBundle().getBundleId());
+        context.addBundleListener(cxfBundleListener);
+        cxfBundleListener.registerExistingBundles(context);
+
+        configAdminTracker = new ServiceTracker<>(context, ConfigurationAdmin.class, null);
+        configAdminTracker.open();
+        workQueues.setConfigAdminTracker(configAdminTracker);
+        workQueueServiceRegistration = registerManagedServiceFactory(context,
+                                                                     ManagedServiceFactory.class,
+                                                                     workQueues,
+                                                                     ManagedWorkQueueList.FACTORY_PID);
+
+        extensions = new ArrayList<>();
+        extensions.add(createOsgiBusListenerExtension(context));
+        extensions.add(createManagedWorkQueueListExtension(workQueues));
+        ExtensionRegistry.addExtensions(extensions);
+
+        BlueprintNameSpaceHandlerFactory factory = new BlueprintNameSpaceHandlerFactory() {
+
+            @Override
+            public Object createNamespaceHandler() {
+                return new CXFAPINamespaceHandler();
+            }
+        };
+        NamespaceHandlerRegisterer.register(context, factory,
+                                            "http://cxf.apache.org/blueprint/core",
+                                            "http://cxf.apache.org/configuration/beans",
+                                            "http://cxf.apache.org/configuration/parameterized-types",
+                                            "http://cxf.apache.org/configuration/security",
+                                            "http://schemas.xmlsoap.org/wsdl/",
+                                            "http://www.w3.org/2005/08/addressing",
+                                            "http://schemas.xmlsoap.org/ws/2004/08/addressing");
+
+    }
+
+    private <T> ServiceRegistration<T> registerManagedServiceFactory(BundleContext context,
+                                                                     Class<T> serviceClass,
+                                                                     T service,
+                                                                     String servicePid) {
+        return context.registerService(serviceClass, service, 
+                                       CollectionUtils.singletonDictionary(Constants.SERVICE_PID, servicePid));
+    }
+
+    private Extension createOsgiBusListenerExtension(BundleContext context) {
+        Extension busListener = new Extension(OSGIBusListener.class);
+        busListener.setArgs(new Object[] {context});
+        return busListener;
+    }
+
+    private static Extension createManagedWorkQueueListExtension(final ManagedWorkQueueList workQueues) {
+        return new Extension(ManagedWorkQueueList.class) {
+            
+            @Override
+            public Object getLoadedObject() {
+                return workQueues;
+            }
+
+            @Override
+            public Extension cloneNoObject() {
+                return this;
+            }
+        };
+    }
+
+    /** {@inheritDoc}*/
+    public void stop(BundleContext context) throws Exception {
+        context.removeBundleListener(cxfBundleListener);
+        cxfBundleListener.shutdown();
+        workQueues.shutDown();
+        workQueueServiceRegistration.unregister();
+        configAdminTracker.close();
+        ExtensionRegistry.removeExtensions(extensions);
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/osgi/CXFExtensionBundleListener.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/osgi/CXFExtensionBundleListener.java
new file mode 100644
index 0000000000..ee9bb15ca1
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/osgi/CXFExtensionBundleListener.java
@@ -0,0 +1,181 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus.osgi;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.logging.Logger;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.bus.extension.Extension;
+import org.apache.cxf.bus.extension.ExtensionException;
+import org.apache.cxf.bus.extension.ExtensionRegistry;
+import org.apache.cxf.bus.extension.TextExtensionFragmentParser;
+import org.apache.cxf.common.i18n.Message;
+import org.apache.cxf.common.logging.LogUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.SynchronousBundleListener;
+
+public class CXFExtensionBundleListener implements SynchronousBundleListener {
+    private static final Logger LOG = LogUtils.getL7dLogger(CXFActivator.class);
+    private long id;
+    private ConcurrentMap<Long, List<OSGiExtension>> extensions
+        = new ConcurrentHashMap<>(16, 0.75f, 4);
+
+    public CXFExtensionBundleListener(long bundleId) {
+        this.id = bundleId;
+    }
+
+    public void registerExistingBundles(BundleContext context) {
+        for (Bundle bundle : context.getBundles()) {
+            if ((bundle.getState() == Bundle.RESOLVED
+                || bundle.getState() == Bundle.STARTING
+                || bundle.getState() == Bundle.ACTIVE
+                || bundle.getState() == Bundle.STOPPING)
+                && bundle.getBundleId() != context.getBundle().getBundleId()) {
+                register(bundle);
+            }
+        }
+    }
+
+    /** {@inheritDoc}*/
+    public void bundleChanged(BundleEvent event) {
+        if (event.getType() == BundleEvent.RESOLVED && id != event.getBundle().getBundleId()) {
+            register(event.getBundle());
+        } else if (event.getType() == BundleEvent.UNRESOLVED || event.getType() == BundleEvent.UNINSTALLED) {
+            unregister(event.getBundle().getBundleId());
+        }
+    }
+
+    protected void register(final Bundle bundle) {
+        Enumeration<?> e = bundle.findEntries("META-INF/cxf/", "bus-extensions.txt", false);
+        while (e != null && e.hasMoreElements()) {
+            List<Extension> orig = new TextExtensionFragmentParser(null).getExtensions((URL)e.nextElement());
+            addExtensions(bundle, orig);
+        }
+    }
+
+    private boolean addExtensions(final Bundle bundle, List<Extension> orig) {
+        if (orig.isEmpty()) {
+            return false;
+        }
+
+        List<String> names = new ArrayList<>(orig.size());
+        for (Extension ext : orig) {
+            names.add(ext.getName());
+        }
+        LOG.info("Adding the extensions from bundle " + bundle.getSymbolicName()
+                 + " (" + bundle.getBundleId() + ") " + names);
+        List<OSGiExtension> list = extensions.get(bundle.getBundleId());
+        if (list == null) {
+            list = new CopyOnWriteArrayList<>();
+            List<OSGiExtension> preList = extensions.putIfAbsent(bundle.getBundleId(), list);
+            if (preList != null) {
+                list = preList;
+            }
+        }
+        for (Extension ext : orig) {
+            list.add(new OSGiExtension(ext, bundle));
+        }
+        ExtensionRegistry.addExtensions(list);
+        return !list.isEmpty();
+    }
+
+    protected void unregister(final long bundleId) {
+        List<OSGiExtension> list = extensions.remove(bundleId);
+        if (list != null) {
+            LOG.info("Removing the extensions for bundle " + bundleId);
+            ExtensionRegistry.removeExtensions(list);
+        }
+    }
+
+    public void shutdown() {
+        while (!extensions.isEmpty()) {
+            unregister(extensions.keySet().iterator().next());
+        }
+    }
+
+    public class OSGiExtension extends Extension {
+        final Bundle bundle;
+        Object serviceObject;
+        public OSGiExtension(Extension e, Bundle b) {
+            super(e);
+            bundle = b;
+        }
+
+        public void setServiceObject(Object o) {
+            serviceObject = o;
+            obj = o;
+        }
+        
+        @Override
+        public Object load(ClassLoader cl, Bus b) {
+            if (interfaceName == null && bundle.getBundleContext() != null) {
+                ServiceReference<?> ref = bundle.getBundleContext().getServiceReference(className);
+                if (ref != null && ref.getBundle().getBundleId() == bundle.getBundleId()) {
+                    Object o = bundle.getBundleContext().getService(ref);
+                    serviceObject = o;
+                    obj = o;
+                    return obj;
+                }
+            }
+            return super.load(cl, b);
+        }
+        
+        @Override
+        protected Class<?> tryClass(String name, ClassLoader cl) {
+            Class<?> c = null;
+            Throwable origExc = null;
+            try {
+                c = bundle.loadClass(className);
+            } catch (Throwable e) {
+                origExc = e;
+            }
+            if (c == null) {
+                try {
+                    return super.tryClass(name, cl);
+                } catch (ExtensionException ee) {
+                    if (origExc != null) {
+                        throw new ExtensionException(new Message("PROBLEM_LOADING_EXTENSION_CLASS",
+                                                                 Extension.LOG, name),
+                                                     origExc);
+                    }
+                    throw ee;
+                }
+            }
+            return c;
+        }
+
+        @Override
+        public Extension cloneNoObject() {
+            OSGiExtension ext = new OSGiExtension(this, bundle);
+            ext.obj = serviceObject;
+            return ext;
+        }
+
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/osgi/OSGIBusListener.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/osgi/OSGIBusListener.java
new file mode 100644
index 0000000000..aad270d042
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/osgi/OSGIBusListener.java
@@ -0,0 +1,224 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus.osgi;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.bus.extension.ExtensionManagerImpl;
+import org.apache.cxf.buslifecycle.BusCreationListener;
+import org.apache.cxf.buslifecycle.BusLifeCycleListener;
+import org.apache.cxf.buslifecycle.BusLifeCycleManager;
+import org.apache.cxf.common.util.CollectionUtils;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.configuration.ConfiguredBeanLocator;
+import org.apache.cxf.endpoint.ClientLifeCycleListener;
+import org.apache.cxf.endpoint.ClientLifeCycleManager;
+import org.apache.cxf.endpoint.ServerLifeCycleListener;
+import org.apache.cxf.endpoint.ServerLifeCycleManager;
+import org.apache.cxf.feature.Feature;
+import org.apache.cxf.workqueue.WorkQueueManager;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.Version;
+
+public class OSGIBusListener implements BusLifeCycleListener {
+    public static final String CONTEXT_SYMBOLIC_NAME_PROPERTY = "cxf.context.symbolicname";
+    public static final String CONTEXT_VERSION_PROPERTY = "cxf.context.version";
+    public static final String CONTEXT_NAME_PROPERTY = "cxf.bus.id";
+
+    private static final String SERVICE_PROPERTY_PRIVATE = "org.apache.cxf.bus.private.extension";
+    private static final String SERVICE_PROPERTY_RESTRICTED = "org.apache.cxf.bus.restricted.extension";
+    private static final String BUS_EXTENSION_BUNDLES_EXCLUDES = "bus.extension.bundles.excludes";
+    Bus bus;
+    ServiceRegistration<?> service;
+    BundleContext defaultContext;
+    private Pattern extensionBundlesExcludesPattern;
+
+    public OSGIBusListener(Bus b) {
+        this(b, null);
+    }
+    public OSGIBusListener(Bus b, Object[] args) {
+        bus = b;
+        if (args != null && args.length > 0
+            && args[0] instanceof BundleContext) {
+            defaultContext = (BundleContext)args[0];
+        }
+        String extExcludes = (String)bus.getProperty(BUS_EXTENSION_BUNDLES_EXCLUDES);
+        if (!StringUtils.isEmpty(extExcludes)) {
+            try {
+                extensionBundlesExcludesPattern = Pattern.compile(extExcludes);
+            } catch (IllegalArgumentException e) {
+                // ignore
+            }
+        }
+        BusLifeCycleManager manager = bus.getExtension(BusLifeCycleManager.class);
+        manager.registerLifeCycleListener(this);
+        registerConfiguredBeanLocator();
+        registerClientLifeCycleListeners();
+        registerServerLifecycleListeners();
+        registerBusFeatures();
+        sendBusCreatedToBusCreationListeners();
+
+    }
+    private void registerConfiguredBeanLocator() {
+        final ConfiguredBeanLocator cbl = bus.getExtension(ConfiguredBeanLocator.class);
+        if (cbl instanceof ExtensionManagerImpl) {
+            // wire in the OSGi things
+            bus.setExtension(new OSGiBeanLocator(cbl, defaultContext),
+                             ConfiguredBeanLocator.class);
+        }
+    }
+
+    public void initComplete() {
+        ManagedWorkQueueList wqList = bus.getExtension(ManagedWorkQueueList.class);
+        if (wqList != null) {
+            WorkQueueManager manager = bus.getExtension(WorkQueueManager.class);
+            wqList.addAllToWorkQueueManager(manager);
+        }
+        registerBusAsService();
+    }
+
+
+    public void preShutdown() {
+    }
+
+    public void postShutdown() {
+        if (service != null) {
+            service.unregister();
+            service = null;
+        }
+    }
+
+    private static ServiceReference<?>[] getServiceReferences(BundleContext context, Class<?> serviceClass) {
+        ServiceReference<?>[] refs = null;
+        try {
+            refs = context.getServiceReferences(serviceClass.getName(), null);
+        } catch (InvalidSyntaxException e) {
+            // ignore
+        }
+        if (refs == null) {
+            refs = new ServiceReference<?>[]{};
+        }
+        return refs;
+    }
+
+    private void sendBusCreatedToBusCreationListeners() {
+        ServiceReference<?>[] refs = getServiceReferences(defaultContext, BusCreationListener.class);
+        for (ServiceReference<?> ref : refs) {
+            if (!isPrivate(ref) && !isExcluded(ref)) {
+                BusCreationListener listener = (BusCreationListener)defaultContext.getService(ref);
+                listener.busCreated(bus);
+            }
+        }
+    }
+
+    private void registerServerLifecycleListeners() {
+        ServiceReference<?>[] refs = getServiceReferences(defaultContext, ServerLifeCycleListener.class);
+        ServerLifeCycleManager clcm = bus.getExtension(ServerLifeCycleManager.class);
+        for (ServiceReference<?> ref : refs) {
+            if (!isPrivate(ref) && !isExcluded(ref)) {
+                ServerLifeCycleListener listener = (ServerLifeCycleListener)defaultContext.getService(ref);
+                clcm.registerListener(listener);
+            }
+        }
+    }
+    private void registerClientLifeCycleListeners() {
+        ServiceReference<?>[] refs = getServiceReferences(defaultContext, ClientLifeCycleListener.class);
+        ClientLifeCycleManager clcm = bus.getExtension(ClientLifeCycleManager.class);
+        for (ServiceReference<?> ref : refs) {
+            if (!isPrivate(ref) && !isExcluded(ref)) {
+                ClientLifeCycleListener listener = (ClientLifeCycleListener)defaultContext.getService(ref);
+                clcm.registerListener(listener);
+            }
+        }
+    }
+
+    private void registerBusFeatures() {
+        ServiceReference<?>[] refs = getServiceReferences(defaultContext, Feature.class);
+        for (ServiceReference<?> ref : refs) {
+            if (!isPrivate(ref) && !isExcluded(ref)) {
+                Feature feature = (Feature)defaultContext.getService(ref);
+                bus.getFeatures().add(feature);
+            }
+        }
+    }
+
+    private boolean isPrivate(ServiceReference<?> ref) {
+        Object o = ref.getProperty(SERVICE_PROPERTY_PRIVATE);
+        
+        if (o == null) {
+            return false;
+        }
+        
+        Boolean pvt = Boolean.FALSE;
+        if (o instanceof String) {
+            pvt = Boolean.parseBoolean((String)o);
+        } else if (o instanceof Boolean) {
+            pvt = (Boolean)o;
+        }
+        return pvt.booleanValue();
+    }
+
+    private boolean isExcluded(ServiceReference<?> ref) {
+        String o = (String)ref.getProperty(SERVICE_PROPERTY_RESTRICTED);
+        if (!StringUtils.isEmpty(o)) {
+            // if the service's restricted-regex is set, the service is excluded when the app not matching that regex
+            BundleContext app = bus.getExtension(BundleContext.class);
+            try {
+                if (app != null && !app.getBundle().getSymbolicName().matches(o)) {
+                    return true;
+                }
+            } catch (IllegalArgumentException e) {
+                // ignore
+            }
+        }
+        // if the excludes-regex is set, the service is excluded when matching that regex.
+        return extensionBundlesExcludesPattern != null
+            && extensionBundlesExcludesPattern.matcher(ref.getBundle().getSymbolicName()).matches();
+    }
+
+    private Version getBundleVersion(Bundle bundle) {
+        Dictionary<?, ?> headers = bundle.getHeaders();
+        String version = (String) headers.get(Constants.BUNDLE_VERSION);
+        return (version != null) ? Version.parseVersion(version) : Version.emptyVersion;
+    }
+
+
+
+    private void registerBusAsService() {
+        BundleContext context = bus.getExtension(BundleContext.class);
+        if (context != null) {
+            Map<String, Object> props = new HashMap<>();
+            props.put(CONTEXT_SYMBOLIC_NAME_PROPERTY, context.getBundle().getSymbolicName());
+            props.put(CONTEXT_VERSION_PROPERTY, getBundleVersion(context.getBundle()));
+            props.put(CONTEXT_NAME_PROPERTY, bus.getId());
+
+            service = context.registerService(Bus.class.getName(), bus, CollectionUtils.toDictionary(props));
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/resource/ResourceManagerImpl.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/resource/ResourceManagerImpl.java
new file mode 100644
index 0000000000..7203e5886b
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/resource/ResourceManagerImpl.java
@@ -0,0 +1,85 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus.resource;
+
+import java.util.List;
+
+import jakarta.annotation.Resource;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.injection.NoJSR250Annotations;
+import org.apache.cxf.configuration.ConfiguredBeanLocator;
+import org.apache.cxf.extension.BusExtension;
+import org.apache.cxf.resource.DefaultResourceManager;
+import org.apache.cxf.resource.ObjectTypeResolver;
+import org.apache.cxf.resource.ResourceManager;
+import org.apache.cxf.resource.ResourceResolver;
+
+@NoJSR250Annotations(unlessNull = "bus")
+public class ResourceManagerImpl extends DefaultResourceManager implements BusExtension {
+
+    private Bus bus;
+
+    public ResourceManagerImpl() {
+    }
+
+    public ResourceManagerImpl(Bus b) {
+        super();
+        setBus(b);
+    }
+    
+    @Override
+    protected void onFirstResolve() {
+        super.onFirstResolve();
+        if (bus != null) {
+            ConfiguredBeanLocator locator = bus.getExtension(ConfiguredBeanLocator.class);
+            if (locator != null) {
+                this.addResourceResolvers(locator.getBeansOfType(ResourceResolver.class));
+            }
+        }
+    }
+
+    /**
+     * Set the list of resolvers for this resource manager.
+     * @param resolvers
+     */
+    public final void setResolvers(List<? extends ResourceResolver> resolvers) {
+        registeredResolvers.clear();
+        registeredResolvers.addAll(resolvers);
+    }
+
+    @Resource
+    public final void setBus(Bus b) {
+        if (bus != b) {
+            bus = b;
+            firstCalled = false;
+            super.addResourceResolver(new ObjectTypeResolver(bus));
+            if (null != bus) {
+                bus.setExtension(this, ResourceManager.class);
+            }
+        }
+    }
+
+    public Class<?> getRegistrationType() {
+        return ResourceManager.class;
+    }
+
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/BusDefinitionParser.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/BusDefinitionParser.java
new file mode 100644
index 0000000000..9d508b62d0
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/BusDefinitionParser.java
@@ -0,0 +1,310 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus.spring;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.w3c.dom.Element;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.injection.NoJSR250Annotations;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.configuration.spring.AbstractBeanDefinitionParser;
+import org.apache.cxf.configuration.spring.BusWiringType;
+import org.apache.cxf.feature.Feature;
+import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.interceptor.AbstractBasicInterceptorProvider;
+import org.apache.cxf.interceptor.Interceptor;
+import org.apache.cxf.message.Message;
+import org.springframework.beans.PropertyValue;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+public class BusDefinitionParser extends AbstractBeanDefinitionParser {
+    private static AtomicInteger counter = new AtomicInteger(0);
+
+    public BusDefinitionParser() {
+        super();
+        setBeanClass(BusConfig.class);
+    }
+
+    @Override
+    protected void doParse(Element element, ParserContext ctx, BeanDefinitionBuilder bean) {
+        String bus = element.getAttribute("bus");
+        if (StringUtils.isEmpty(bus)) {
+            bus = element.getAttribute("name");
+            if (StringUtils.isEmpty(bus)) {
+                element.setAttribute("bus", bus);
+            }
+        }
+        element.removeAttribute("name");
+        if (StringUtils.isEmpty(bus)) {
+            bus = "cxf";
+        }
+        String id = element.getAttribute("id");
+        if (!StringUtils.isEmpty(id)) {
+            bean.addPropertyValue("id", id);
+        }
+
+        super.doParse(element, ctx, bean);
+
+        if (ctx.getRegistry().containsBeanDefinition(bus)) {
+            BeanDefinition def = ctx.getRegistry().getBeanDefinition(bus);
+            copyProps(bean, def);
+            bean.addConstructorArgValue(bus);
+        } else if (!"cxf".equals(bus)) {
+            bean.getRawBeanDefinition().setBeanClass(SpringBus.class);
+            bean.setDestroyMethodName("shutdown");
+            try {
+                element.setUserData("ID", bus, null);
+                bean.getRawBeanDefinition().getPropertyValues().removePropertyValue("bus");
+            } catch (Throwable t) {
+                //likely not DOM level 3, ignore
+            }
+        } else {
+            addBusWiringAttribute(bean, BusWiringType.PROPERTY, bus, ctx);
+            bean.getRawBeanDefinition().setAttribute(WIRE_BUS_CREATE,
+                                                     resolveId(element, null, ctx));
+            bean.addConstructorArgValue(bus);
+        }
+    }
+    
+    @Override
+    protected boolean processBusAttribute(Element element, ParserContext ctx,
+                                          BeanDefinitionBuilder bean,
+                                          String val) {
+        return false;
+    }
+    
+    private void copyProps(BeanDefinitionBuilder src, BeanDefinition def) {
+        for (PropertyValue v : src.getBeanDefinition().getPropertyValues().getPropertyValues()) {
+            if (!"bus".equals(v.getName())) {
+                def.getPropertyValues().addPropertyValue(v.getName(), v.getValue());
+            }
+            src.getBeanDefinition().getPropertyValues().removePropertyValue(v);
+        }
+
+    }
+
+    @Override
+    protected void mapElement(ParserContext ctx,
+                              BeanDefinitionBuilder bean,
+                              Element e,
+                              String name) {
+        if ("inInterceptors".equals(name) || "inFaultInterceptors".equals(name)
+            || "outInterceptors".equals(name) || "outFaultInterceptors".equals(name)
+            || "features".equals(name)) {
+            List<?> list = ctx.getDelegate().parseListElement(e, bean.getBeanDefinition());
+            bean.addPropertyValue(name, list);
+        } else if ("properties".equals(name)) {
+            Map<?, ?> map = ctx.getDelegate().parseMapElement(e, bean.getBeanDefinition());
+            bean.addPropertyValue("properties", map);
+        }
+    }
+    @Override
+    protected String resolveId(Element element, AbstractBeanDefinition definition,
+                               ParserContext ctx) {
+        String bus = null;
+        try {
+            bus = (String)element.getUserData("ID");
+        } catch (Throwable t) {
+            //ignore
+        }
+        if (bus == null) {
+            bus = element.getAttribute("bus");
+            if (StringUtils.isEmpty(bus)) {
+                bus = element.getAttribute("name");
+            }
+            if (StringUtils.isEmpty(bus)) {
+                bus = Bus.DEFAULT_BUS_ID + ".config" + counter.getAndIncrement();
+            } else {
+                bus = bus + ".config";
+            }
+            try {
+                element.setUserData("ID", bus, null);
+            } catch (Throwable t) {
+                //maybe no DOM level 3, ignore, but, may have issues with the counter
+            }
+        }
+        return bus;
+    }
+
+    @NoJSR250Annotations
+    public static class BusConfig extends AbstractBasicInterceptorProvider
+        implements ApplicationContextAware {
+
+        Bus bus;
+        String busName;
+        String id;
+        Collection<Feature> features;
+        Map<String, Object> properties;
+
+        public BusConfig(String busName) {
+            this.busName = busName;
+        }
+
+        public void setBus(Bus bb) {
+            if (bus == bb) {
+                return;
+            }
+            if (properties != null) {
+                bb.setProperties(properties);
+                properties = null;
+            }
+            if (!getInInterceptors().isEmpty()) {
+                bb.getInInterceptors().addAll(getInInterceptors());
+            }
+            if (!getOutInterceptors().isEmpty()) {
+                bb.getOutInterceptors().addAll(getOutInterceptors());
+            }
+            if (!getInFaultInterceptors().isEmpty()) {
+                bb.getInFaultInterceptors().addAll(getInFaultInterceptors());
+            }
+            if (!getOutFaultInterceptors().isEmpty()) {
+                bb.getOutFaultInterceptors().addAll(getOutFaultInterceptors());
+            }
+            if (!StringUtils.isEmpty(id)) {
+                bb.setId(id);
+            }
+            if (features != null) {
+                bb.setFeatures(features);
+                features = null;
+            }
+            bus = bb;
+        }
+
+        public void setApplicationContext(ApplicationContext applicationContext) {
+            if (bus != null) {
+                return;
+            }
+        }
+
+        @Override
+        public List<Interceptor<? extends Message>> getOutFaultInterceptors() {
+            if (bus != null) {
+                return bus.getOutFaultInterceptors();
+            }
+            return super.getOutFaultInterceptors();
+        }
+
+        @Override
+        public List<Interceptor<? extends Message>> getInFaultInterceptors() {
+            if (bus != null) {
+                return bus.getInFaultInterceptors();
+            }
+            return super.getInFaultInterceptors();
+        }
+
+        @Override
+        public List<Interceptor<? extends Message>> getInInterceptors() {
+            if (bus != null) {
+                return bus.getInInterceptors();
+            }
+            return super.getInInterceptors();
+        }
+
+        @Override
+        public List<Interceptor<? extends Message>> getOutInterceptors() {
+            if (bus != null) {
+                return bus.getOutInterceptors();
+            }
+            return super.getOutInterceptors();
+        }
+
+        @Override
+        public void setInInterceptors(List<Interceptor<? extends Message>> interceptors) {
+            if (bus != null) {
+                bus.getInInterceptors().addAll(interceptors);
+            } else {
+                super.setInInterceptors(interceptors);
+            }
+        }
+
+        @Override
+        public void setInFaultInterceptors(List<Interceptor<? extends Message>> interceptors) {
+            if (bus != null) {
+                bus.getInFaultInterceptors().addAll(interceptors);
+            } else {
+                super.setInFaultInterceptors(interceptors);
+            }
+        }
+
+        @Override
+        public void setOutInterceptors(List<Interceptor<? extends Message>> interceptors) {
+            if (bus != null) {
+                bus.getOutInterceptors().addAll(interceptors);
+            } else {
+                super.setOutInterceptors(interceptors);
+            }
+        }
+
+        @Override
+        public void setOutFaultInterceptors(List<Interceptor<? extends Message>> interceptors) {
+            if (bus != null) {
+                bus.getOutFaultInterceptors().addAll(interceptors);
+            } else {
+                super.setOutFaultInterceptors(interceptors);
+            }
+        }
+
+        public Collection<Feature> getFeatures() {
+            if (bus != null) {
+                return bus.getFeatures();
+            }
+            return features;
+        }
+
+        public void setFeatures(Collection<? extends Feature> features) {
+            if (bus != null) {
+                bus.setFeatures(features);
+            } else {
+                this.features = CastUtils.cast(features);
+            }
+
+        }
+
+        public Map<String, Object> getProperties() {
+            if (bus != null) {
+                return bus.getProperties();
+            }
+            return properties;
+        }
+        public void setProperties(Map<String, Object> s) {
+            if (bus != null) {
+                bus.setProperties(s);
+            } else {
+                this.properties = s;
+            }
+        }
+
+        public void setId(String s) {
+            id = s;
+        }
+
+
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/BusEntityResolver.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/BusEntityResolver.java
new file mode 100644
index 0000000000..1e95e286b7
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/BusEntityResolver.java
@@ -0,0 +1,94 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus.spring;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.springframework.beans.factory.xml.DelegatingEntityResolver;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PropertiesLoaderUtils;
+import org.springframework.util.CollectionUtils;
+
+/**
+ *
+ */
+public class BusEntityResolver extends DelegatingEntityResolver  {
+
+    private static final Logger LOG = LogUtils.getL7dLogger(BusEntityResolver.class);
+
+    private EntityResolver dtdResolver;
+    private EntityResolver schemaResolver;
+    private Map<String, String> schemaMappings;
+    private ClassLoader classLoader;
+
+    public BusEntityResolver(ClassLoader loader, EntityResolver dr, EntityResolver sr) {
+        super(dr, sr);
+        classLoader = loader;
+        dtdResolver = dr;
+        schemaResolver = sr;
+
+        try {
+            Properties mappings = PropertiesLoaderUtils.loadAllProperties("META-INF/spring.schemas",
+                                                                          classLoader);
+            schemaMappings = new ConcurrentHashMap<>(mappings.size());
+            CollectionUtils.mergePropertiesIntoMap(mappings, schemaMappings);
+        } catch (IOException e) {
+            //ignore
+        }
+    }
+
+    @Override
+    public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
+        InputSource source = super.resolveEntity(publicId, systemId);
+        if (null == source && null != systemId) {
+            // try the schema and dtd resolver in turn, ignoring the suffix in publicId
+            LOG.log(Level.FINE, "Attempting to resolve systemId {0}", systemId);
+            source = schemaResolver.resolveEntity(publicId, systemId);
+            if (null == source) {
+                source = dtdResolver.resolveEntity(publicId, systemId);
+            }
+        }
+        
+        if (null == source) {
+            return null;
+        }
+        
+        String resourceLocation = schemaMappings.get(systemId);
+        if (resourceLocation != null && publicId == null) {
+            Resource resource = new ClassPathResource(resourceLocation, classLoader);
+            if (resource.exists()) {
+                source.setPublicId(systemId);
+                source.setSystemId(resource.getURL().toString());
+            }
+        }
+        return source;
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/BusExtensionPostProcessor.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/BusExtensionPostProcessor.java
new file mode 100644
index 0000000000..9389be6b49
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/BusExtensionPostProcessor.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus.spring;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.injection.NoJSR250Annotations;
+import org.apache.cxf.extension.BusExtension;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.Ordered;
+
+@NoJSR250Annotations
+public class BusExtensionPostProcessor implements BeanPostProcessor, ApplicationContextAware, Ordered {
+
+    private Bus bus;
+    private ApplicationContext context;
+
+    public void setApplicationContext(ApplicationContext ctx) {
+        context = ctx;
+    }
+
+    public int getOrder() {
+        return 1001;
+    }
+
+
+    @Override
+    public Object postProcessAfterInitialization(Object bean, String beanId) {
+        return bean;
+    }
+
+    @Override
+    public Object postProcessBeforeInitialization(Object bean, String beanId) {
+        if (bean instanceof BusExtension && null != getBus()) {
+            Class<? extends Object> cls = ((BusExtension)bean).getRegistrationType();
+            registerExt(bean, cls);
+        } else if (bean instanceof Bus && Bus.DEFAULT_BUS_ID.equals(beanId)) {
+            bus = (Bus)bean;
+        }
+        return bean;
+    }
+    private <T> void registerExt(Object bean, Class<T> cls) {
+        getBus().setExtension(cls.cast(bean), cls);
+    }
+
+    private Bus getBus() {
+        if (bus == null) {
+            bus = (Bus)context.getBean(Bus.DEFAULT_BUS_ID);
+        }
+        return bus;
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/Jsr250BeanPostProcessor.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/Jsr250BeanPostProcessor.java
new file mode 100644
index 0000000000..1fb0746eb8
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/Jsr250BeanPostProcessor.java
@@ -0,0 +1,164 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus.spring;
+
+
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.injection.ResourceInjector;
+import org.apache.cxf.resource.ResourceManager;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.Ordered;
+
+public class Jsr250BeanPostProcessor
+    implements DestructionAwareBeanPostProcessor, Ordered, ApplicationContextAware {
+
+    private ResourceManager resourceManager;
+    private ApplicationContext context;
+
+    private boolean isProcessing = true;
+    //private int count;
+    //private int count2;
+
+    Jsr250BeanPostProcessor() {
+    }
+
+    public void setApplicationContext(ApplicationContext applicationContext) {
+        context = applicationContext;
+        try {
+            Class<?> cls = Class
+                .forName("org.springframework.context.annotation.CommonAnnotationBeanPostProcessor");
+            isProcessing = context.getBeanNamesForType(cls, true, false).length == 0;
+        } catch (ClassNotFoundException e) {
+            isProcessing = true;
+        }
+    }
+
+    public int getOrder() {
+        return 1010;
+    }
+
+    private boolean injectable(Object bean, String beanId) {
+        return !"cxf".equals(beanId) && ResourceInjector.processable(bean.getClass(), bean);
+    }
+    private ResourceManager getResourceManager(Object bean) {
+        if (resourceManager == null) {
+            boolean temp = isProcessing;
+            isProcessing = false;
+            if (bean instanceof ResourceManager) {
+                resourceManager = (ResourceManager)bean;
+                resourceManager.addResourceResolver(new BusApplicationContextResourceResolver(context));
+            } else if (bean instanceof Bus) {
+                Bus b = (Bus)bean;
+                ResourceManager m = b.getExtension(ResourceManager.class);
+                if (m != null) {
+                    resourceManager = m;
+                    if (!(b instanceof SpringBus)) {
+                        resourceManager
+                            .addResourceResolver(new BusApplicationContextResourceResolver(context));
+                    }
+                }
+            } else {
+                ResourceManager m = null;
+                Bus b = null;
+                try {
+                    m = (ResourceManager)context.getBean(ResourceManager.class.getName());
+                } catch (NoSuchBeanDefinitionException t) {
+                    //ignore - no resource manager
+                }
+                if (m == null) {
+                    b = (Bus)context.getBean("cxf");
+                    m = b.getExtension(ResourceManager.class);
+                }
+                if (m != null) {
+                    resourceManager = m;
+                    if (!(b instanceof SpringBus)) {
+                        resourceManager
+                            .addResourceResolver(new BusApplicationContextResourceResolver(context));
+                    }
+                }
+            }
+            isProcessing = temp;
+        }
+        return resourceManager;
+    }
+    
+    @Override
+    public Object postProcessAfterInitialization(Object bean, String beanId) {
+        if (!isProcessing) {
+            if (resourceManager == null && bean instanceof ResourceManager) {
+                resourceManager = (ResourceManager)bean;
+                resourceManager.addResourceResolver(new BusApplicationContextResourceResolver(context));
+            }
+            return bean;
+        }
+        if (bean != null
+            && injectable(bean, beanId)) {
+            new ResourceInjector(getResourceManager(bean)).construct(bean);
+        }
+        return bean;
+    }
+
+    @Override
+    public Object postProcessBeforeInitialization(Object bean, String beanId) {
+        if (!isProcessing) {
+            return bean;
+        }
+        if (bean instanceof Bus) {
+            getResourceManager(bean);
+        }
+        /*
+        if (bean.getClass().getName().contains("Corb")) {
+            Thread.dumpStack();
+        }
+        */
+
+        if (bean != null
+            && injectable(bean, beanId)) {
+            new ResourceInjector(getResourceManager(bean)).inject(bean);
+            /*
+            System.out.println("p :" + (++count) + ": " + bean.getClass().getName() + " " + beanId);
+        } else if (bean != null) {
+            System.out.println("np: " + (++count2)
+                               + ": " + bean.getClass().getName() + " " + beanId);
+                               */
+        }
+        return bean;
+    }
+
+    public void postProcessBeforeDestruction(Object bean, String beanId) {
+        if (!isProcessing) {
+            return;
+        }
+        if (bean != null
+            && injectable(bean, beanId)) {
+            new ResourceInjector(getResourceManager(bean)).destroy(bean);
+        }
+    }
+
+    @Override
+    public boolean requiresDestruction(Object bean) {
+        return isProcessing;
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/NamespaceHandler.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/NamespaceHandler.java
new file mode 100644
index 0000000000..9211ea8411
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/NamespaceHandler.java
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus.spring;
+
+import org.w3c.dom.Element;
+
+import org.apache.cxf.configuration.spring.SimpleBeanDefinitionParser;
+import org.apache.cxf.feature.FastInfosetFeature;
+import org.apache.cxf.workqueue.AutomaticWorkQueueImpl;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
+import org.springframework.beans.factory.xml.ParserContext;
+
+public class NamespaceHandler extends NamespaceHandlerSupport {
+    @SuppressWarnings("deprecation")
+    public void init() {
+        registerBeanDefinitionParser("bus",
+                                     new BusDefinitionParser());
+        registerBeanDefinitionParser("logging",
+                                     new SimpleBeanDefinitionParser(org.apache.cxf.feature.LoggingFeature.class));
+        registerBeanDefinitionParser("fastinfoset",
+                                     new SimpleBeanDefinitionParser(FastInfosetFeature.class));
+
+        registerBeanDefinitionParser("workqueue",
+                                     new SimpleBeanDefinitionParser(AutomaticWorkQueueImpl.class) {
+
+                @Override
+                protected void processNameAttribute(Element element,
+                                                ParserContext ctx,
+                                                BeanDefinitionBuilder bean,
+                                                String val) {
+                    bean.addPropertyValue("name", val);
+                    element.removeAttribute("name");
+                    if (!element.hasAttribute("id")) {
+                        element.setAttribute("id", "cxf.workqueue." + val);
+                    }
+
+                }
+            });
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/SpringBus.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/SpringBus.java
new file mode 100644
index 0000000000..6616c8ed85
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/bus/spring/SpringBus.java
@@ -0,0 +1,142 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.bus.spring;
+
+import org.apache.cxf.bus.extension.ExtensionManagerBus;
+import org.apache.cxf.configuration.ConfiguredBeanLocator;
+import org.apache.cxf.configuration.Configurer;
+import org.apache.cxf.configuration.spring.ConfigurerImpl;
+import org.apache.cxf.resource.ResourceManager;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextClosedEvent;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.context.support.AbstractApplicationContext;
+
+/**
+ *
+ */
+public class SpringBus extends ExtensionManagerBus
+    implements ApplicationContextAware {
+
+    AbstractApplicationContext ctx;
+    boolean closeContext;
+
+    public SpringBus() {
+    }
+
+    public void setBusConfig(BusDefinitionParser.BusConfig bc) {
+        bc.setBus(this);
+    }
+
+    /** {@inheritDoc}*/
+    public void setApplicationContext(ApplicationContext applicationContext) {
+        ctx = (AbstractApplicationContext)applicationContext;
+        @SuppressWarnings("rawtypes")
+        ApplicationListener listener = new ApplicationListener() {
+            public void onApplicationEvent(ApplicationEvent event) {
+                SpringBus.this.onApplicationEvent(event);
+            }
+        };
+        ctx.addApplicationListener(listener);
+        ApplicationContext ac = applicationContext.getParent();
+        while (ac != null) {
+            if (ac instanceof AbstractApplicationContext) {
+                ((AbstractApplicationContext)ac).addApplicationListener(listener);
+            }
+            ac = ac.getParent();
+        }
+
+        // set the classLoader extension with the application context classLoader
+        setExtension(applicationContext.getClassLoader(), ClassLoader.class);
+
+        setExtension(new ConfigurerImpl(applicationContext), Configurer.class);
+
+        ResourceManager m = getExtension(ResourceManager.class);
+        m.addResourceResolver(new BusApplicationContextResourceResolver(applicationContext));
+
+        setExtension(applicationContext, ApplicationContext.class);
+        ConfiguredBeanLocator loc = getExtension(ConfiguredBeanLocator.class);
+        if (!(loc instanceof SpringBeanLocator)) {
+            setExtension(new SpringBeanLocator(applicationContext, this), ConfiguredBeanLocator.class);
+        }
+        if (getState() != BusState.RUNNING) {
+            initialize();
+        }
+    }
+
+    public void onApplicationEvent(ApplicationEvent event) {
+        if (ctx == null) {
+            return;
+        }
+        boolean doIt = false;
+        ApplicationContext ac = ctx;
+        while (ac != null) {
+            if (event.getSource() == ac) {
+                doIt = true;
+                break;
+            }
+            ac = ac.getParent();
+        }
+        if (doIt) {
+            if (event instanceof ContextRefreshedEvent) {
+                if (getState() != BusState.RUNNING) {
+                    initialize();
+                }
+            } else if (event instanceof ContextClosedEvent && getState() == BusState.RUNNING) {
+                // The bus could be create by using SpringBusFactory.createBus("/cxf.xml");
+                // Just to make sure the shutdown is called rightly
+                shutdown();
+            }
+        }
+    }
+
+    @Override
+    public void destroyBeans() {
+        if (closeContext) {
+            ctx.close();
+        }
+        super.destroyBeans();
+    }
+
+    @Override
+    public String getId() {
+        if (id == null) {
+            try {
+                Class<?> clsbc = Class.forName("org.osgi.framework.BundleContext");
+                Class<?> clsb = Class.forName("org.osgi.framework.Bundle");
+                Object o = getExtension(clsbc);
+                Object o2 = clsbc.getMethod("getBundle").invoke(o);
+                String s = (String)clsb.getMethod("getSymbolicName").invoke(o2);
+                id = s + '-' + DEFAULT_BUS_ID + Integer.toString(this.hashCode());
+            } catch (Throwable t) {
+                id = super.getId();
+            }
+        }
+        return id;
+    }
+
+    public void setCloseContext(boolean b) {
+        closeContext = b;
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/catalog/CatalogXmlSchemaURIResolver.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/catalog/CatalogXmlSchemaURIResolver.java
new file mode 100644
index 0000000000..15a3ce2e39
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/catalog/CatalogXmlSchemaURIResolver.java
@@ -0,0 +1,102 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.catalog;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.xml.sax.InputSource;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.resource.ExtendedURIResolver;
+import org.apache.cxf.transport.TransportURIResolver;
+import org.apache.ws.commons.schema.XmlSchemaException;
+import org.apache.ws.commons.schema.resolver.URIResolver;
+
+/**
+ * Resolves URIs using Apache Commons Resolver API.
+ */
+public class CatalogXmlSchemaURIResolver implements URIResolver {
+
+    private ExtendedURIResolver resolver;
+    private Bus bus;
+    private Map<String, String> resolved = new HashMap<>();
+
+    public CatalogXmlSchemaURIResolver(Bus bus) {
+        this.resolver = new TransportURIResolver(bus);
+        this.bus = bus;
+    }
+
+    public Map<String, String> getResolvedMap() {
+        return resolved;
+    }
+
+    public InputSource resolveEntity(String targetNamespace, String schemaLocation, String baseUri) {
+        final String resolvedSchemaLocation;
+        OASISCatalogManager catalogResolver = OASISCatalogManager.getCatalogManager(bus);
+        try {
+            resolvedSchemaLocation = new OASISCatalogManagerHelper().resolve(catalogResolver,
+                                          schemaLocation, baseUri);
+        } catch (Exception e) {
+            throw new RuntimeException("Catalog resolution failed", e);
+        }
+
+        final InputSource in;
+        if (resolvedSchemaLocation == null) {
+            in = this.resolver.resolve(schemaLocation, baseUri);
+        } else {
+            resolved.put(schemaLocation, resolvedSchemaLocation);
+            in = this.resolver.resolve(resolvedSchemaLocation, baseUri);
+        }
+
+        // If we return null, a NPE is raised in SchemaBuilder.
+        // If we return new InputSource(), a XmlSchemaException is raised
+        // but without any nice error message. So let's just throw a nice error here.
+        if (in == null) {
+            throw new XmlSchemaException("Unable to locate imported document "
+                                         + "at '" + schemaLocation + "'"
+                                         + (baseUri == null
+                                            ? "."
+                                            : ", relative to '" + baseUri + "'."));
+        } else if (in.getByteStream() != null
+            && !(in.getByteStream() instanceof ByteArrayInputStream)) {
+            //workaround bug in XmlSchema - XmlSchema is not closing the InputStreams
+            //that are returned for imports.  Thus, with a lot of services starting up
+            //or a lot of schemas imported or similar, it's easy to run out of
+            //file handles.  We'll just load the file into a byte[] and return that.
+            try {
+                InputStream ins = IOUtils.loadIntoBAIS(in.getByteStream());
+                in.setByteStream(ins);
+            } catch (IOException e) {
+                throw new XmlSchemaException("Unable to load imported document "
+                                             + "at '" + schemaLocation + "'"
+                                             + (baseUri == null
+                                                ? "."
+                                                : ", relative to '" + baseUri + "'."),
+                                                e);
+            }
+        }
+
+        return in;
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/configuration/jsse/MultiKeyPasswordKeyManager.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/configuration/jsse/MultiKeyPasswordKeyManager.java
new file mode 100644
index 0000000000..6a1aee5fb5
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/configuration/jsse/MultiKeyPasswordKeyManager.java
@@ -0,0 +1,84 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.configuration.jsse;
+
+import java.net.Socket;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.X509KeyManager;
+
+public class MultiKeyPasswordKeyManager implements X509KeyManager {
+    private final KeyStore mKeyStore;
+    private final String mKeyAlias;
+    private final String mKeyPassword;
+
+    public MultiKeyPasswordKeyManager(KeyStore keystore, String keyAlias, String keyPassword) {
+        mKeyStore = keystore;
+        mKeyAlias = keyAlias;
+        mKeyPassword = keyPassword;
+    }
+
+    public String[] getClientAliases(String keyType, Principal[] issuers) {
+        return new String[] {
+            mKeyAlias
+        };
+    }
+
+    public String[] getServerAliases(String keyType, Principal[] issuers) {
+        return new String[] {
+            mKeyAlias
+        };
+    }
+    public X509Certificate[] getCertificateChain(String alias) {
+        final Certificate[] chain;
+        try {
+            chain = mKeyStore.getCertificateChain(alias);
+        } catch (KeyStoreException kse) {
+            throw new RuntimeException(kse);
+        }
+        final X509Certificate[] certChain = new X509Certificate[chain.length];
+        for (int i = 0; i < chain.length; i++) {
+            certChain[i] = (X509Certificate)chain[i];
+        }
+        return certChain;
+    }
+
+    public PrivateKey getPrivateKey(String alias) {
+        try {
+            return (PrivateKey)mKeyStore.getKey(alias, mKeyPassword.toCharArray());
+        } catch (GeneralSecurityException gse) {
+            throw new RuntimeException(gse);
+        }
+    }
+
+    public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
+        return mKeyAlias;
+    }
+
+    public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
+        return mKeyAlias;
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/configuration/jsse/TLSClientParameters.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/configuration/jsse/TLSClientParameters.java
new file mode 100644
index 0000000000..3e0099a126
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/configuration/jsse/TLSClientParameters.java
@@ -0,0 +1,258 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.configuration.jsse;
+
+import java.util.List;
+import java.util.Objects;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * This class extends {@link TLSParameterBase} with client-specific
+ * SSL/TLS parameters.
+ *
+ */
+public class TLSClientParameters extends TLSParameterBase {
+    private boolean disableCNCheck;
+    private SSLSocketFactory sslSocketFactory;
+    private int sslCacheTimeout = 86400;
+    private boolean useHttpsURLConnectionDefaultSslSocketFactory;
+    private boolean useHttpsURLConnectionDefaultHostnameVerifier;
+    private HostnameVerifier hostnameVerifier;
+    private SSLContext sslContext;
+
+    /**
+     * Set custom HostnameVerifier
+     * @param verifier hostname verifier
+     */
+    public void setHostnameVerifier(HostnameVerifier verifier) {
+        hostnameVerifier = verifier;
+    }
+
+    /**
+     * Get custom HostnameVerifier
+     * @return hostname verifier
+     */
+    public HostnameVerifier getHostnameVerifier() {
+        return hostnameVerifier;
+    }
+    /**
+     * Set whether or not JSEE should omit checking if the host name
+     * specified in the URL matches that of the Common Name
+     * (CN) on the server's certificate. Default is false;
+     * this attribute should not be set to true during production use.
+     */
+    public void setDisableCNCheck(boolean disableCNCheck) {
+        this.disableCNCheck = disableCNCheck;
+    }
+
+    /**
+     * Returns whether or not JSSE omits checking if the
+     * host name specified in the URL matches that of the Common Name
+     * (CN) on the server's certificate.
+     */
+    public boolean isDisableCNCheck() {
+        return disableCNCheck;
+    }
+
+    /**
+     * This sets the SSLSocketFactory to use, causing all other properties of
+     * this bean (and its superclass) to get ignored (this takes precendence).
+     */
+    public final void setSSLSocketFactory(SSLSocketFactory factory) {
+        sslSocketFactory = factory;
+    }
+
+
+    /**
+     * Returns the SSLSocketFactory to be used, or null if none has been set.
+     */
+    public final SSLSocketFactory getSSLSocketFactory() {
+        return sslSocketFactory;
+    }
+
+    /**
+     * Returns the SSL cache timeout in seconds if it has been configured or the default value
+     */
+    public int getSslCacheTimeout() {
+        return sslCacheTimeout;
+    }
+
+    /**
+     * This sets the SSL Session Cache timeout value in seconds for client sessions handled by CXF
+     */
+    public void setSslCacheTimeout(int sslCacheTimeout) {
+        this.sslCacheTimeout = sslCacheTimeout;
+    }
+
+
+    /**
+     * Returns whether or not {@link javax.net.ssl.HttpsURLConnection#getDefaultSSLSocketFactory()} should be
+     * used to create https connections. If <code>true</code> , {@link #getJsseProvider()} ,
+     * {@link #getSecureSocketProtocol()}, {@link #getTrustManagers()}, {@link #getKeyManagers()},
+     * {@link #getSecureRandom()}, {@link #getCipherSuites()} and {@link #getCipherSuitesFilter()} are
+     * ignored.
+     */
+    public boolean isUseHttpsURLConnectionDefaultSslSocketFactory() {
+        return useHttpsURLConnectionDefaultSslSocketFactory;
+    }
+
+    /**
+     * Sets whether or not {@link javax.net.ssl.HttpsURLConnection#getDefaultSSLSocketFactory()} should be
+     * used to create https connections.
+     *
+     * @see #isUseHttpsURLConnectionDefaultSslSocketFactory()
+     */
+    public void setUseHttpsURLConnectionDefaultSslSocketFactory(
+                      boolean useHttpsURLConnectionDefaultSslSocketFactory) {
+        this.useHttpsURLConnectionDefaultSslSocketFactory = useHttpsURLConnectionDefaultSslSocketFactory;
+    }
+
+    /**
+     * Returns whether or not {@link javax.net.ssl.HttpsURLConnection#getDefaultHostnameVerifier()} should be
+     * used to create https connections. If <code>true</code>, {@link #isDisableCNCheck()} is ignored.
+     */
+    public boolean isUseHttpsURLConnectionDefaultHostnameVerifier() {
+        return useHttpsURLConnectionDefaultHostnameVerifier;
+    }
+
+    /**
+     * Sets whether or not {@link javax.net.ssl.HttpsURLConnection#getDefaultHostnameVerifier()} should be
+     * used to create https connections.
+     *
+     * @see #isUseHttpsURLConnectionDefaultHostnameVerifier()
+     */
+    public void setUseHttpsURLConnectionDefaultHostnameVerifier(
+                      boolean useHttpsURLConnectionDefaultHostnameVerifier) {
+        this.useHttpsURLConnectionDefaultHostnameVerifier = useHttpsURLConnectionDefaultHostnameVerifier;
+    }
+
+    public int hashCode() {
+        int hash = disableCNCheck ? 37 : 17;
+        if (sslSocketFactory != null) {
+            hash = hash * 41 + System.identityHashCode(sslSocketFactory);
+        }
+        if (sslContext != null) {
+            hash = hash * 41 + System.identityHashCode(sslContext);
+        }
+        hash = hash(hash, useHttpsURLConnectionDefaultSslSocketFactory);
+        hash = hash(hash, useHttpsURLConnectionDefaultHostnameVerifier);
+        hash = hash(hash, sslCacheTimeout);
+        hash = hash(hash, secureRandom);
+        hash = hash(hash, protocol);
+        hash = hash(hash, certAlias);
+        hash = hash(hash, provider);
+        for (String cs : ciphersuites) {
+            hash = hash(hash, cs);
+        }
+        hash = hash(hash, keyManagers);
+        hash = hash(hash, trustManagers);
+        if (cipherSuiteFilters != null) {
+            hash = hash(hash, cipherSuiteFilters.getInclude());
+            hash = hash(hash, cipherSuiteFilters.getExclude());
+        }
+        if (certConstraints != null) {
+            hash = hash(hash, certConstraints.getIssuerDNConstraints());
+            hash = hash(hash, certConstraints.getSubjectDNConstraints());
+        }
+        return hash;
+    }
+    private int hash(int i, Object o) {
+        if (o != null) {
+            return i * 37 + o.hashCode();
+        }
+        return i;
+    }
+    private int hash(int i, Object[] os) {
+        if (os == null) {
+            return i;
+        }
+        for (Object o : os) {
+            i = hash(i, o);
+        }
+        return i;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (o instanceof TLSClientParameters) {
+            TLSClientParameters that = (TLSClientParameters)o;
+            boolean eq = disableCNCheck == that.disableCNCheck;
+            eq &= sslSocketFactory == that.sslSocketFactory;
+            eq &= sslContext == that.sslContext;
+            eq &= useHttpsURLConnectionDefaultSslSocketFactory == that.useHttpsURLConnectionDefaultSslSocketFactory;
+            eq &= useHttpsURLConnectionDefaultHostnameVerifier == that.useHttpsURLConnectionDefaultHostnameVerifier;
+            eq &= sslCacheTimeout == that.sslCacheTimeout;
+            eq &= secureRandom == that.secureRandom;
+            eq &= Objects.equals(certAlias, that.certAlias);
+            eq &= Objects.equals(protocol, that.protocol);
+            eq &= Objects.equals(provider, that.provider);
+            eq &= equals(ciphersuites, that.ciphersuites);
+            eq &= Objects.deepEquals(keyManagers, that.keyManagers);
+            eq &= Objects.deepEquals(trustManagers, that.trustManagers);
+            if (cipherSuiteFilters != null) {
+                if (that.cipherSuiteFilters != null) {
+                    eq &= equals(cipherSuiteFilters.getExclude(), that.cipherSuiteFilters.getExclude());
+                    eq &= equals(cipherSuiteFilters.getInclude(), that.cipherSuiteFilters.getInclude());
+                } else {
+                    eq = false;
+                }
+            } else {
+                eq &= that.cipherSuiteFilters == null;
+            }
+            if (certConstraints != null) {
+                if (that.certConstraints != null) {
+                    eq &= Objects.equals(certConstraints.getIssuerDNConstraints(),
+                                 that.certConstraints.getIssuerDNConstraints());
+                    eq &= Objects.equals(certConstraints.getSubjectDNConstraints(),
+                                 that.certConstraints.getSubjectDNConstraints());
+                } else {
+                    eq = false;
+                }
+            } else {
+                eq &= that.certConstraints == null;
+            }
+            return eq;
+        }
+        return false;
+    }
+
+    private static boolean equals(final List<?> obj1, final List<?> obj2) {
+        return obj1.equals(obj2);
+    }
+
+    /**
+     * Get the SSLContext parameter to use (if it has been set)
+     */
+    public SSLContext getSslContext() {
+        return sslContext;
+    }
+
+    /**
+     * Set an SSLContext parameter to use to create https connections
+     */
+    public void setSslContext(SSLContext sslContext) {
+        this.sslContext = sslContext;
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/configuration/jsse/TLSParameterJaxBUtils.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/configuration/jsse/TLSParameterJaxBUtils.java
new file mode 100644
index 0000000000..bd16aa436a
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/configuration/jsse/TLSParameterJaxBUtils.java
@@ -0,0 +1,420 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.configuration.jsse;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Paths;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.net.ssl.CertPathTrustManagerParameters;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.PasswordCallback;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.common.classloader.ClassLoaderUtils;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.configuration.security.CertStoreType;
+import org.apache.cxf.configuration.security.KeyManagersType;
+import org.apache.cxf.configuration.security.KeyStoreType;
+import org.apache.cxf.configuration.security.SecureRandomParameters;
+import org.apache.cxf.configuration.security.TrustManagersType;
+import org.apache.cxf.resource.ResourceManager;
+
+/**
+ * This class provides some functionality to convert the JAXB
+ * generated types in the security.xsd to the items needed
+ * to programatically configure the HTTPConduit and HTTPDestination
+ * with TLSClientParameters and TLSServerParameters respectively.
+ */
+public final class TLSParameterJaxBUtils {
+
+    private static final Logger LOG =
+        LogUtils.getL7dLogger(TLSParameterJaxBUtils.class);
+
+    private TLSParameterJaxBUtils() {
+        // empty
+    }
+    /**
+     * This method converts the JAXB generated type into a SecureRandom.
+     */
+    public static SecureRandom getSecureRandom(
+            SecureRandomParameters secureRandomParams
+    ) throws GeneralSecurityException {
+
+        SecureRandom secureRandom = null;
+        if (secureRandomParams != null) {
+            String secureRandomAlg =
+                secureRandomParams.getAlgorithm();
+            String randomProvider =
+                secureRandomParams.getProvider();
+            if (randomProvider != null) {
+                secureRandom = secureRandomAlg != null
+                               ? SecureRandom.getInstance(
+                                       secureRandomAlg,
+                                       randomProvider)
+                               : null;
+            } else {
+                secureRandom = secureRandomAlg != null
+                               ? SecureRandom.getInstance(
+                                       secureRandomAlg)
+                               : null;
+            }
+        }
+        return secureRandom;
+    }
+
+    public static KeyStore getKeyStore(KeyStoreType kst) throws GeneralSecurityException, IOException {
+        return getKeyStore(kst, false);
+    }
+
+    /**
+     * This method converts a JAXB generated KeyStoreType into a KeyStore.
+     */
+    public static KeyStore getKeyStore(KeyStoreType kst, boolean trustStore)
+        throws GeneralSecurityException,
+               IOException {
+
+        if (kst == null) {
+            return null;
+        }
+        final String type;
+        if (trustStore) {
+            type = SSLUtils.getTrustStoreType(kst.isSetType()
+                                     ? kst.getType() : null, LOG, KeyStore.getDefaultType());
+        } else {
+            type = SSLUtils.getKeystoreType(kst.isSetType()
+                                 ? kst.getType() : null, LOG, KeyStore.getDefaultType());
+        }
+
+        char[] password = kst.isSetPassword()
+                    ? deobfuscate(kst.getPassword())
+                    : null;
+        if (password == null) {
+            final String tmp;
+            if (trustStore) {
+                tmp = SSLUtils.getTruststorePassword(null, LOG);
+            } else {
+                tmp = SSLUtils.getKeystorePassword(null, LOG);
+            }
+            if (tmp != null) {
+                password = tmp.toCharArray();
+            }
+        }
+        final String provider;
+        if (trustStore) {
+            provider = SSLUtils.getTruststoreProvider(kst.isSetProvider() ? kst.getProvider() : null, LOG);
+        } else {
+            provider = SSLUtils.getKeystoreProvider(kst.isSetProvider() ? kst.getProvider() : null, LOG);
+        }
+        KeyStore keyStore = provider == null
+                    ? KeyStore.getInstance(type)
+                    : KeyStore.getInstance(type, provider);
+
+        if (kst.isSetFile()) {
+            try (InputStream kstInputStream = Files.newInputStream(Paths.get(kst.getFile()))) {
+                keyStore.load(kstInputStream, password);
+            }
+        } else if (kst.isSetResource()) {
+            final InputStream is = getResourceAsStream(kst.getResource());
+            if (is == null) {
+                final String msg =
+                    "Could not load keystore resource " + kst.getResource();
+                LOG.severe(msg);
+                throw new IOException(msg);
+            }
+            keyStore.load(is, password);
+        } else if (kst.isSetUrl()) {
+            keyStore.load(new URL(kst.getUrl()).openStream(), password);
+        } else {
+            final String loc;
+            if (trustStore) {
+                loc = SSLUtils.getTruststore(null, LOG);
+            } else {
+                loc = SSLUtils.getKeystore(null, LOG);
+            }
+            if (loc != null) {
+                try (InputStream ins = Files.newInputStream(Paths.get(loc))) {
+                    keyStore.load(ins, password);
+                } catch (NoSuchFileException ex) {
+                    // Fall back to load the location as a stream
+                    try (InputStream ins = getResourceAsStream(loc)) {
+                        keyStore.load(ins, password);
+                    }
+                }
+            }
+        }
+        return keyStore;
+    }
+
+    /**
+     * This method converts a JAXB generated CertStoreType into a KeyStore.
+     */
+    public static KeyStore getKeyStore(final CertStoreType pst)
+        throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException {
+
+        if (pst == null) {
+            return null;
+        }
+        String type;
+        if (pst.isSetType()) {
+            type = pst.getType();
+        } else {
+            type = KeyStore.getDefaultType();
+        }
+        if (pst.isSetFile()) {
+            InputStream is = Files.newInputStream(Paths.get(pst.getFile()));
+            return createTrustStore(is, type);
+        }
+        if (pst.isSetResource()) {
+            final InputStream is = getResourceAsStream(pst.getResource());
+            if (is == null) {
+                final String msg =
+                    "Could not load truststore resource " + pst.getResource();
+                LOG.severe(msg);
+                throw new IOException(msg);
+            }
+            return createTrustStore(is, type);
+        }
+        if (pst.isSetUrl()) {
+            return createTrustStore(new URL(pst.getUrl()).openStream(), type);
+        }
+        throw new IllegalArgumentException("Could not create KeyStore based on information in CertStoreType");
+    }
+
+    private static InputStream getResourceAsStream(String resource) {
+        InputStream is = ClassLoaderUtils.getResourceAsStream(resource, TLSParameterJaxBUtils.class);
+        if (is == null) {
+            Bus bus = BusFactory.getThreadDefaultBus(true);
+            ResourceManager rm = bus.getExtension(ResourceManager.class);
+            if (rm != null) {
+                is = rm.getResourceAsStream(resource);
+            }
+        }
+        return is;
+    }
+
+    /**
+     * Create a KeyStore containing the trusted CA certificates contained
+     * in the supplied input stream.
+     */
+    private static KeyStore createTrustStore(final InputStream is, String type)
+        throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException {
+
+        final Collection<? extends Certificate> certs = loadCertificates(is);
+        final KeyStore keyStore =
+            KeyStore.getInstance(type);
+        keyStore.load(null, null);
+        for (Certificate cert : certs) {
+            final X509Certificate xcert = (X509Certificate) cert;
+            keyStore.setCertificateEntry(
+                xcert.getSubjectX500Principal().getName(),
+                cert
+            );
+        }
+        return keyStore;
+    }
+
+    /**
+     * load the certificates as X.509 certificates
+     */
+    private static Collection<? extends Certificate> loadCertificates(final InputStream is)
+        throws IOException, CertificateException {
+
+        final CertificateFactory factory = CertificateFactory.getInstance("X.509");
+        return factory.generateCertificates(is);
+    }
+
+    private static char[] deobfuscate(String s) {
+        // From the Jetty org.eclipse.jetty.http.security.Password class
+        if (!s.startsWith("OBF:")) {
+            return s.toCharArray();
+        }
+        s = s.substring(4);
+
+        char[] b = new char[s.length() / 2];
+        int l = 0;
+        for (int i = 0; i < s.length(); i += 4) {
+            String x = s.substring(i, i + 4);
+            int i0 = Integer.parseInt(x, 36);
+            int i1 = i0 / 256;
+            int i2 = i0 % 256;
+            b[l++] = (char) ((i1 + i2 - 254) / 2);
+        }
+
+        return new String(b, 0, l).toCharArray();
+    }
+
+    /**
+     * This method converts the JAXB KeyManagersType into a list of
+     * JSSE KeyManagers.
+     */
+    public static KeyManager[] getKeyManagers(KeyManagersType kmc)
+        throws GeneralSecurityException,
+               IOException {
+
+        KeyStore keyStore = getKeyStore(kmc.getKeyStore(), false);
+
+        String alg = kmc.isSetFactoryAlgorithm()
+                     ? kmc.getFactoryAlgorithm()
+                     : KeyManagerFactory.getDefaultAlgorithm();
+
+        char[] keyPass = getKeyPassword(kmc);
+
+        KeyManagerFactory fac =
+                     kmc.isSetProvider()
+                     ? KeyManagerFactory.getInstance(alg, kmc.getProvider())
+                     : KeyManagerFactory.getInstance(alg);
+
+        fac.init(keyStore, keyPass);
+
+        return fac.getKeyManagers();
+    }
+
+    /**
+     * This method converts the JAXB KeyManagersType into a list of
+     * JSSE KeyManagers.
+     */
+    public static KeyManager[] getKeyManagers(KeyManagersType kmc, String alias)
+        throws GeneralSecurityException,
+               IOException {
+
+        KeyStore keyStore = getKeyStore(kmc.getKeyStore(), false);
+
+        String alg = kmc.isSetFactoryAlgorithm()
+                     ? kmc.getFactoryAlgorithm()
+                     : KeyManagerFactory.getDefaultAlgorithm();
+
+        char[] keyPass = getKeyPassword(kmc);
+
+        KeyManagerFactory fac =
+                     kmc.isSetProvider()
+                     ? KeyManagerFactory.getInstance(alg, kmc.getProvider())
+                     : KeyManagerFactory.getInstance(alg);
+
+        try {
+            fac.init(keyStore, keyPass);
+
+            return fac.getKeyManagers();
+        } catch (java.security.UnrecoverableKeyException uke) {
+            //jsse has the restriction that different key in keystore
+            //cannot has different password, use MultiKeyPasswordKeyManager
+            //as fallback when this happen
+            MultiKeyPasswordKeyManager manager
+                = new MultiKeyPasswordKeyManager(keyStore, alias,
+                                             new String(keyPass));
+            return new KeyManager[]{manager};
+        }
+    }
+
+    private static char[] getKeyPassword(KeyManagersType kmc) {
+        char[] keyPass = kmc.isSetKeyPassword()
+            ? deobfuscate(kmc.getKeyPassword())
+            : null;
+
+        if (keyPass != null) {
+            return keyPass;
+        }
+
+        String callbackHandlerClass = kmc.getKeyPasswordCallbackHandler();
+        if (callbackHandlerClass == null) {
+            return null;
+        }
+        try {
+            final CallbackHandler ch = (CallbackHandler) ClassLoaderUtils
+                .loadClass(callbackHandlerClass, TLSParameterJaxBUtils.class).newInstance();
+            String prompt = kmc.getKeyStore().getFile();
+            if (prompt == null) {
+                prompt = kmc.getKeyStore().getResource();
+            }
+            PasswordCallback pwCb = new PasswordCallback(prompt, false);
+            PasswordCallback[] callbacks = new PasswordCallback[] {pwCb};
+            ch.handle(callbacks);
+            keyPass = callbacks[0].getPassword();
+        } catch (Exception e) {
+            LOG.log(Level.WARNING,
+                    "Cannot load key password from callback handler: " + e.getMessage(), e);
+        }
+        return keyPass;
+    }
+
+    /**
+     * This method converts the JAXB TrustManagersType into a list of
+     * JSSE TrustManagers.
+     */
+    @Deprecated
+    public static TrustManager[] getTrustManagers(TrustManagersType tmc)
+        throws GeneralSecurityException,
+               IOException {
+        return getTrustManagers(tmc, false);
+    }
+
+    public static TrustManager[] getTrustManagers(TrustManagersType tmc, boolean enableRevocation)
+        throws GeneralSecurityException,
+               IOException {
+
+        final KeyStore keyStore =
+            tmc.isSetKeyStore()
+                ? getKeyStore(tmc.getKeyStore(), true)
+                : (tmc.isSetCertStore()
+                    ? getKeyStore(tmc.getCertStore())
+                    : null);
+
+        String alg = tmc.isSetFactoryAlgorithm()
+                     ? tmc.getFactoryAlgorithm()
+                     : TrustManagerFactory.getDefaultAlgorithm();
+
+        TrustManagerFactory fac =
+                     tmc.isSetProvider()
+                     ? TrustManagerFactory.getInstance(alg, tmc.getProvider())
+                     : TrustManagerFactory.getInstance(alg);
+
+        if (enableRevocation) {
+            PKIXBuilderParameters param = new PKIXBuilderParameters(keyStore, new X509CertSelector());
+            param.setRevocationEnabled(true);
+
+            fac.init(new CertPathTrustManagerParameters(param));
+        } else {
+            fac.init(keyStore);
+        }
+
+        return fac.getTrustManagers();
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/configuration/spring/ConfigurerImpl.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/configuration/spring/ConfigurerImpl.java
new file mode 100644
index 0000000000..d920936f81
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/configuration/spring/ConfigurerImpl.java
@@ -0,0 +1,288 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.configuration.spring;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.apache.cxf.common.injection.NoJSR250Annotations;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.configuration.Configurable;
+import org.apache.cxf.configuration.Configurer;
+import org.apache.cxf.extension.BusExtension;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.AbstractBeanFactory;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.beans.factory.wiring.BeanConfigurerSupport;
+import org.springframework.beans.factory.wiring.BeanWiringInfo;
+import org.springframework.beans.factory.wiring.BeanWiringInfoResolver;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ConfigurableApplicationContext;
+
+@NoJSR250Annotations
+public class ConfigurerImpl extends BeanConfigurerSupport
+    implements Configurer, ApplicationContextAware, BusExtension {
+
+    private static final Logger LOG = LogUtils.getL7dLogger(ConfigurerImpl.class);
+
+    private Set<ApplicationContext> appContexts;
+    private final Map<String, List<MatcherHolder>> wildCardBeanDefinitions = new TreeMap<>();
+    private BeanFactory beanFactory;
+
+    static class MatcherHolder implements Comparable<MatcherHolder> {
+        Matcher matcher;
+        String wildCardId;
+        MatcherHolder(String orig, Matcher matcher) {
+            wildCardId = orig;
+            this.matcher = matcher;
+        }
+        
+        @Override
+        public int compareTo(MatcherHolder mh) {
+            int literalCharsLen1 = this.wildCardId.replace("*", "").length();
+            int literalCharsLen2 = mh.wildCardId.replace("*", "").length();
+            // The expression with more literal characters should end up on the top of the list
+            return Integer.compare(literalCharsLen1, literalCharsLen2) * -1;
+        }
+    }
+
+    public ConfigurerImpl() {
+        // complete
+    }
+
+    public ConfigurerImpl(ApplicationContext ac) {
+        setApplicationContext(ac);
+    }
+
+    @Override
+    public void setBeanFactory(BeanFactory beanFactory) {
+        this.beanFactory = beanFactory;
+        super.setBeanFactory(beanFactory);
+    }
+
+    private void initWildcardDefinitionMap() {
+        if (null != appContexts) {
+            for (ApplicationContext appContext : appContexts) {
+                for (String n : appContext.getBeanDefinitionNames()) {
+                    if (isWildcardBeanName(n)) {
+                        AutowireCapableBeanFactory bf = appContext.getAutowireCapableBeanFactory();
+                        BeanDefinitionRegistry bdr = (BeanDefinitionRegistry) bf;
+                        BeanDefinition bd = bdr.getBeanDefinition(n);
+                        String className = bd.getBeanClassName();
+                        if (null != className) {
+                            final String name = n.charAt(0) != '*' ? n
+                                    : "." + n.replaceAll("\\.", "\\."); //old wildcard
+                            try {
+                                Matcher matcher = Pattern.compile(name).matcher("");
+                                List<MatcherHolder> m = wildCardBeanDefinitions.get(className);
+                                if (m == null) {
+                                    m = new ArrayList<>();
+                                    wildCardBeanDefinitions.put(className, m);
+                                }
+                                MatcherHolder holder = new MatcherHolder(n, matcher);
+                                m.add(holder);
+                            } catch (PatternSyntaxException npe) {
+                                //not a valid patter, we'll ignore
+                            }
+                        } else {
+                            LogUtils.log(LOG, Level.WARNING, "WILDCARD_BEAN_ID_WITH_NO_CLASS_MSG", n);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public void configureBean(Object beanInstance) {
+        configureBean(null, beanInstance, true);
+    }
+
+    public void configureBean(String bn, Object beanInstance) {
+        configureBean(bn, beanInstance, true);
+    }
+    public synchronized void configureBean(String bn, Object beanInstance, boolean checkWildcards) {
+
+        if (null == appContexts) {
+            return;
+        }
+
+        if (null == bn) {
+            bn = getBeanName(beanInstance);
+            if (null == bn) {
+                return;
+            }
+        }
+
+        if (checkWildcards) {
+            configureWithWildCard(bn, beanInstance);
+        }
+
+        final String beanName = bn;
+        setBeanWiringInfoResolver(new BeanWiringInfoResolver() {
+            public BeanWiringInfo resolveWiringInfo(Object instance) {
+                if (!beanName.isEmpty()) {
+                    return new BeanWiringInfo(beanName);
+                }
+                return null;
+            }
+        });
+
+        for (ApplicationContext appContext : appContexts) {
+            if (appContext.containsBean(bn)) {
+                this.setBeanFactory(appContext.getAutowireCapableBeanFactory());
+            }
+        }
+
+        try {
+            //this will prevent a call into the AbstractBeanFactory.markBeanAsCreated(...)
+            //which saves ALL the names into a HashSet.  For URL based configuration,
+            //this can leak memory
+            if (beanFactory instanceof AbstractBeanFactory) {
+                ((AbstractBeanFactory)beanFactory).getMergedBeanDefinition(bn);
+            }
+            super.configureBean(beanInstance);
+            if (LOG.isLoggable(Level.FINE)) {
+                LOG.fine("Successfully performed injection.");
+            }
+        } catch (NoSuchBeanDefinitionException ex) {
+            // users often wonder why the settings in their configuration files seem
+            // to have no effect - the most common cause is that they have been using
+            // incorrect bean ids
+            if (LOG.isLoggable(Level.FINE)) {
+                LOG.log(Level.FINE, "NO_MATCHING_BEAN_MSG", beanName);
+            }
+        }
+    }
+
+    private void configureWithWildCard(String bn, Object beanInstance) {
+        if (!wildCardBeanDefinitions.isEmpty()) {
+            Class<?> clazz = beanInstance.getClass();
+            while (!Object.class.equals(clazz)) {
+                String className = clazz.getName();
+                List<MatcherHolder> matchers = wildCardBeanDefinitions.get(className);
+                if (matchers != null) {
+                    for (MatcherHolder m : matchers) {
+                        synchronized (m.matcher) {
+                            m.matcher.reset(bn);
+                            if (m.matcher.matches()) {
+                                configureBean(m.wildCardId, beanInstance, false);
+                                return;
+                            }
+                        }
+                    }
+                }
+                clazz = clazz.getSuperclass();
+            }
+        }
+    }
+
+    private boolean isWildcardBeanName(String bn) {
+        return bn.indexOf('*') != -1 || bn.indexOf('?') != -1
+            || (bn.indexOf('(') != -1 && bn.indexOf(')') != -1);
+    }
+
+    protected String getBeanName(Object beanInstance) {
+        if (beanInstance instanceof Configurable) {
+            return ((Configurable)beanInstance).getBeanName();
+        }
+        String beanName = null;
+        Method m = null;
+        try {
+            m = beanInstance.getClass().getDeclaredMethod("getBeanName", (Class[])null);
+        } catch (NoSuchMethodException ex) {
+            try {
+                m = beanInstance.getClass().getMethod("getBeanName", (Class[])null);
+            } catch (NoSuchMethodException e) {
+                //ignore
+            }
+        }
+        if (m != null) {
+            try {
+                beanName = (String)(m.invoke(beanInstance));
+            } catch (Exception ex) {
+                LogUtils.log(LOG, Level.WARNING, "ERROR_DETERMINING_BEAN_NAME_EXC", ex);
+            }
+        }
+
+        if (null == beanName) {
+            LogUtils.log(LOG, Level.FINE, "COULD_NOT_DETERMINE_BEAN_NAME_MSG",
+                         beanInstance.getClass().getName());
+        }
+
+        return beanName;
+    }
+
+    public final void setApplicationContext(ApplicationContext ac) {
+        appContexts = new CopyOnWriteArraySet<>();
+        addApplicationContext(ac);
+        this.beanFactory = ac.getAutowireCapableBeanFactory();
+        super.setBeanFactory(this.beanFactory);
+    }
+
+    public final void addApplicationContext(ApplicationContext ac) {
+        if (!appContexts.contains(ac)) {
+            appContexts.add(ac);
+            List<ApplicationContext> inactiveApplicationContexts = new ArrayList<>();
+            Iterator<ApplicationContext> it = appContexts.iterator();
+            while (it.hasNext()) {
+                ApplicationContext c = it.next();
+                if (c instanceof ConfigurableApplicationContext
+                    && !((ConfigurableApplicationContext)c).isActive()) {
+                    inactiveApplicationContexts.add(c);
+                }
+            }
+            // Remove the inactive application context here can avoid the UnsupportedOperationException
+            for (ApplicationContext context : inactiveApplicationContexts) {
+                appContexts.remove(context);
+            }
+            initWildcardDefinitionMap();
+        }
+    }
+
+    @Override
+    public void destroy() {
+        super.destroy();
+        appContexts.clear();
+    }
+
+    public Class<?> getRegistrationType() {
+        return Configurer.class;
+    }
+
+    protected Set<ApplicationContext> getAppContexts() {
+        return appContexts;
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/databinding/source/SourceDataBinding.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/databinding/source/SourceDataBinding.java
new file mode 100644
index 0000000000..5321779f80
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/databinding/source/SourceDataBinding.java
@@ -0,0 +1,104 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.databinding.source;
+
+
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.w3c.dom.Node;
+
+import org.apache.cxf.common.xmlschema.SchemaCollection;
+import org.apache.cxf.databinding.DataReader;
+import org.apache.cxf.databinding.DataWriter;
+import org.apache.cxf.service.Service;
+import org.apache.cxf.service.ServiceModelVisitor;
+import org.apache.cxf.service.model.MessagePartInfo;
+import org.apache.cxf.service.model.ServiceInfo;
+import org.apache.ws.commons.schema.constants.Constants;
+
+/**
+ * A simple databinding implementation which reads and writes Source objects.
+ */
+public class SourceDataBinding extends org.apache.cxf.databinding.AbstractDataBinding {
+
+    public static final String PREFERRED_FORMAT = "source-preferred-format";
+
+    final Class<?> preferred;
+
+    public SourceDataBinding() {
+        super();
+        preferred = null;
+    }
+    public SourceDataBinding(Class<?> pref) {
+        super();
+        preferred = pref;
+    }
+
+    public void initialize(Service service) {
+        for (ServiceInfo serviceInfo : service.getServiceInfos()) {
+            SchemaCollection schemaCollection = serviceInfo.getXmlSchemaCollection();
+            if (schemaCollection.getXmlSchemas().length > 1) {
+                // Schemas are already populated.
+                continue;
+            }
+            new ServiceModelVisitor(serviceInfo) {
+                @Override
+                public void begin(MessagePartInfo part) {
+                    if (part.getTypeQName() != null || part.getElementQName() != null) {
+                        return;
+                    }
+                    part.setTypeQName(Constants.XSD_ANYTYPE);
+                }
+            } .walk();
+        }
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public <T> DataReader<T> createReader(Class<T> cls) {
+        if (cls == XMLStreamReader.class) {
+            return (DataReader<T>) new XMLStreamDataReader(preferred);
+        } else if (cls == Node.class) {
+            return (DataReader<T>) new NodeDataReader();
+        } else {
+            throw new UnsupportedOperationException("The type " + cls.getName() + " is not supported.");
+        }
+    }
+
+    public Class<?>[] getSupportedReaderFormats() {
+        return new Class<?>[] {XMLStreamReader.class, Node.class};
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> DataWriter<T> createWriter(Class<T> cls) {
+        if (cls == XMLStreamWriter.class) {
+            return (DataWriter<T>) new XMLStreamDataWriter();
+        } else if (cls == Node.class) {
+            return (DataWriter<T>) new NodeDataWriter();
+        }
+        throw new UnsupportedOperationException("The type " + cls.getName() + " is not supported.");
+    }
+
+    public Class<?>[] getSupportedWriterFormats() {
+        return new Class<?>[] {XMLStreamWriter.class, Node.class};
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/databinding/stax/StaxDataBinding.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/databinding/stax/StaxDataBinding.java
new file mode 100644
index 0000000000..3cb836b8b0
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/databinding/stax/StaxDataBinding.java
@@ -0,0 +1,187 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.databinding.stax;
+
+import java.util.Collection;
+import java.util.logging.Logger;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.validation.Schema;
+
+import org.w3c.dom.Node;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.xmlschema.SchemaCollection;
+import org.apache.cxf.databinding.AbstractInterceptorProvidingDataBinding;
+import org.apache.cxf.databinding.DataReader;
+import org.apache.cxf.databinding.DataWriter;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.interceptor.StaxInEndingInterceptor;
+import org.apache.cxf.message.Attachment;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.AbstractPhaseInterceptor;
+import org.apache.cxf.phase.Phase;
+import org.apache.cxf.service.Service;
+import org.apache.cxf.service.ServiceModelVisitor;
+import org.apache.cxf.service.model.MessagePartInfo;
+import org.apache.cxf.service.model.ServiceInfo;
+import org.apache.cxf.staxutils.StaxUtils;
+import org.apache.ws.commons.schema.constants.Constants;
+
+/**
+ * A simple databinding implementation which reads and writes Source objects.
+ * This will not work with the standard databinding interceptors.
+ */
+public class StaxDataBinding extends AbstractInterceptorProvidingDataBinding {
+
+    private XMLStreamDataReader xsrReader;
+    private XMLStreamDataWriter xswWriter;
+
+    public StaxDataBinding() {
+        super();
+        this.xsrReader = new XMLStreamDataReader();
+        this.xswWriter = new XMLStreamDataWriter();
+        inInterceptors.add(new StaxInEndingInterceptor(Phase.POST_INVOKE));
+        inFaultInterceptors.add(new StaxInEndingInterceptor(Phase.POST_INVOKE));
+
+        inInterceptors.add(RemoveStaxInEndingInterceptor.INSTANCE);
+        inFaultInterceptors.add(RemoveStaxInEndingInterceptor.INSTANCE);
+    }
+
+    static class RemoveStaxInEndingInterceptor extends AbstractPhaseInterceptor<Message> {
+        static final RemoveStaxInEndingInterceptor INSTANCE = new RemoveStaxInEndingInterceptor();
+
+        RemoveStaxInEndingInterceptor() {
+            super(Phase.PRE_INVOKE);
+            addBefore(StaxInEndingInterceptor.class.getName());
+        }
+
+        public void handleMessage(Message message) {
+            message.getInterceptorChain().remove(StaxInEndingInterceptor.INSTANCE);
+        }
+    }
+
+
+    public void initialize(Service service) {
+        for (ServiceInfo serviceInfo : service.getServiceInfos()) {
+            SchemaCollection schemaCollection = serviceInfo.getXmlSchemaCollection();
+            if (schemaCollection.getXmlSchemas().length > 1) {
+                // Schemas are already populated.
+                continue;
+            }
+            new ServiceModelVisitor(serviceInfo) {
+                
+                @Override
+                public void begin(MessagePartInfo part) {
+                    if (part.getTypeQName() != null || part.getElementQName() != null) {
+                        return;
+                    }
+                    part.setTypeQName(Constants.XSD_ANYTYPE);
+                }
+            } .walk();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> DataReader<T> createReader(Class<T> cls) {
+        if (cls == XMLStreamReader.class) {
+            return (DataReader<T>) xsrReader;
+        }
+        throw new UnsupportedOperationException("The type " + cls.getName() + " is not supported.");
+    }
+
+    public Class<?>[] getSupportedReaderFormats() {
+        return new Class<?>[] {XMLStreamReader.class};
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> DataWriter<T> createWriter(Class<T> cls) {
+        if (cls == XMLStreamWriter.class) {
+            return (DataWriter<T>) xswWriter;
+        }
+        throw new UnsupportedOperationException("The type " + cls.getName() + " is not supported.");
+    }
+
+    public Class<?>[] getSupportedWriterFormats() {
+        return new Class<?>[] {XMLStreamWriter.class, Node.class};
+    }
+
+    public static class XMLStreamDataReader implements DataReader<XMLStreamReader> {
+
+        public Object read(MessagePartInfo part, XMLStreamReader input) {
+            return read(null, input, part.getTypeClass());
+        }
+
+        public Object read(QName name, XMLStreamReader input, Class<?> type) {
+            return input;
+        }
+
+        public Object read(XMLStreamReader reader) {
+            return reader;
+        }
+
+        public void setSchema(Schema s) {
+        }
+
+        public void setAttachments(Collection<Attachment> attachments) {
+        }
+
+        public void setProperty(String prop, Object value) {
+        }
+    }
+
+    public static class XMLStreamDataWriter implements DataWriter<XMLStreamWriter> {
+        private static final Logger LOG = LogUtils.getL7dLogger(XMLStreamDataWriter.class);
+
+        public void write(Object obj, MessagePartInfo part, XMLStreamWriter output) {
+            write(obj, output);
+        }
+
+        public void write(Object obj, XMLStreamWriter writer) {
+            try {
+                if (obj instanceof XMLStreamReader) {
+                    XMLStreamReader xmlStreamReader = (XMLStreamReader) obj;
+                    StaxUtils.copy(xmlStreamReader, writer);
+                    xmlStreamReader.close();
+                } else if (obj instanceof XMLStreamWriterCallback) {
+                    ((XMLStreamWriterCallback) obj).write(writer);
+                } else {
+                    throw new UnsupportedOperationException("Data types of "
+                                                            + obj.getClass() + " are not supported.");
+                }
+            } catch (XMLStreamException e) {
+                throw new Fault("COULD_NOT_READ_XML_STREAM", LOG, e);
+            }
+        }
+
+        public void setSchema(Schema s) {
+        }
+
+        public void setAttachments(Collection<Attachment> attachments) {
+        }
+
+        public void setProperty(String key, Object value) {
+        }
+
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/endpoint/AbstractConduitSelector.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/endpoint/AbstractConduitSelector.java
new file mode 100644
index 0000000000..250e523b11
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/endpoint/AbstractConduitSelector.java
@@ -0,0 +1,308 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.endpoint;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.logging.Logger;
+
+import org.apache.cxf.BusException;
+import org.apache.cxf.common.util.PropertyUtils;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.message.Exchange;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageUtils;
+import org.apache.cxf.service.model.EndpointInfo;
+import org.apache.cxf.transport.Conduit;
+import org.apache.cxf.transport.ConduitInitiator;
+import org.apache.cxf.transport.ConduitInitiatorManager;
+import org.apache.cxf.transport.MessageObserver;
+import org.apache.cxf.ws.addressing.AttributedURIType;
+import org.apache.cxf.ws.addressing.EndpointReferenceType;
+
+
+/**
+ * Abstract base class holding logic common to any ConduitSelector
+ * that retrieves a Conduit from the ConduitInitiator.
+ */
+public abstract class AbstractConduitSelector implements ConduitSelector, Closeable {
+    public static final String CONDUIT_COMPARE_FULL_URL
+        = "org.apache.cxf.ConduitSelector.compareFullUrl";
+    protected static final String KEEP_CONDUIT_ALIVE = "KeepConduitAlive";
+
+
+    //collection of conduits that were created so we can close them all at the end
+    protected List<Conduit> conduits = new CopyOnWriteArrayList<>();
+
+   
+    protected Endpoint endpoint;
+
+
+    public AbstractConduitSelector() {
+    }
+
+    /**
+     * Constructor, allowing a specific conduit to override normal selection.
+     *
+     * @param c specific conduit
+     */
+    public AbstractConduitSelector(Conduit c) {
+        if (c != null) {
+            conduits.add(c);
+        }
+    }
+
+    public void close() {
+        for (Conduit c : conduits) {
+            c.close();
+        }
+        conduits.clear();
+    }
+
+    protected void removeConduit(Conduit conduit) {
+        if (conduit != null) {
+            conduit.close();
+            conduits.remove(conduit);
+        }
+    }
+
+    /**
+     * Mechanics to actually get the Conduit from the ConduitInitiator
+     * if necessary.
+     *
+     * @param message the current Message
+     */
+    protected Conduit getSelectedConduit(Message message) {
+        Conduit c = findCompatibleConduit(message);
+        if (c == null) {
+            Exchange exchange = message.getExchange();
+            EndpointInfo ei = endpoint.getEndpointInfo();
+            String transportID = ei.getTransportId();
+            try {
+                ConduitInitiatorManager conduitInitiatorMgr = exchange.getBus()
+                    .getExtension(ConduitInitiatorManager.class);
+                if (conduitInitiatorMgr != null) {
+                    ConduitInitiator conduitInitiator =
+                        conduitInitiatorMgr.getConduitInitiator(transportID);
+                    if (conduitInitiator != null) {
+                        c = createConduit(message, exchange, conduitInitiator);
+                    } else {
+                        getLogger().warning("ConduitInitiator not found: "
+                                            + ei.getAddress());
+                    }
+                } else {
+                    getLogger().warning("ConduitInitiatorManager not found");
+                }
+            } catch (BusException | IOException ex) {
+                throw new Fault(ex);
+            }
+        }
+        if (c != null && c.getTarget() != null && c.getTarget().getAddress() != null) {
+            replaceEndpointAddressPropertyIfNeeded(message, c.getTarget().getAddress().getValue(), c);
+        }
+        //the search for the conduit could cause extra properties to be reset/loaded.
+        message.resetContextCache();
+        message.put(Conduit.class, c);
+        return c;
+    }
+
+    protected Conduit createConduit(Message message, Exchange exchange, ConduitInitiator conduitInitiator)
+        throws IOException {
+        Conduit c;
+        synchronized (endpoint) {
+            if (!conduits.isEmpty()) {
+                c = findCompatibleConduit(message);
+                if (c != null) {
+                    return c;
+                }
+            }
+            EndpointInfo ei = endpoint.getEndpointInfo();
+            String add = (String)message.get(Message.ENDPOINT_ADDRESS);
+            String basePath = (String)message.get(Message.BASE_PATH);
+            if (StringUtils.isEmpty(add)
+                || add.equals(ei.getAddress())) {
+                c = conduitInitiator.getConduit(ei, exchange.getBus());
+                replaceEndpointAddressPropertyIfNeeded(message, add, c);
+            } else {
+                EndpointReferenceType epr = new EndpointReferenceType();
+                AttributedURIType ad = new AttributedURIType();
+                ad.setValue(StringUtils.isEmpty(basePath) ? add : basePath);
+                epr.setAddress(ad);
+                c = conduitInitiator.getConduit(ei, epr, exchange.getBus());
+            }
+            MessageObserver observer =
+                exchange.get(MessageObserver.class);
+            if (observer != null) {
+                c.setMessageObserver(observer);
+            } else {
+                getLogger().warning("MessageObserver not found");
+            }
+            conduits.add(c);
+        }
+        return c;
+    }
+
+    // Some conduits may replace the endpoint address after it has already been prepared
+    // but before the invocation has been done (ex, org.apache.cxf.clustering.LoadDistributorTargetSelector)
+    // which may affect JAX-RS clients where actual endpoint address property may include additional path
+    // segments.
+    protected boolean replaceEndpointAddressPropertyIfNeeded(Message message,
+                                                             String endpointAddress,
+                                                             Conduit cond) {
+        return false;
+    }
+
+    /**
+     * @return the encapsulated Endpoint
+     */
+    public Endpoint getEndpoint() {
+        return endpoint;
+    }
+
+    /**
+     * @param ep the endpoint to encapsulate
+     */
+    public void setEndpoint(Endpoint ep) {
+        endpoint = ep;
+    }
+
+    /**
+     * Called on completion of the MEP for which the Conduit was required.
+     *
+     * @param exchange represents the completed MEP
+     */
+    public void complete(Exchange exchange) {
+        // Clients expecting explicit InputStream responses
+        // will need to keep low level conduits operating on InputStreams open
+        // and will be responsible for closing the streams
+
+        if (PropertyUtils.isTrue(exchange.get(KEEP_CONDUIT_ALIVE))) {
+            return;
+        }
+        try {
+            if (exchange.getInMessage() != null) {
+                Conduit c = exchange.getOutMessage().get(Conduit.class);
+                if (c == null) {
+                    getSelectedConduit(exchange.getInMessage()).close(exchange.getInMessage());
+                } else {
+                    c.close(exchange.getInMessage());
+                }
+            }
+        } catch (IOException e) {
+            //IGNORE
+        }
+    }
+    /**
+     * @return the logger to use
+     */
+    protected abstract Logger getLogger();
+
+    /**
+     * If address protocol was changed, conduit should be re-initialised
+     *
+     * @param message the current Message
+     */
+    protected Conduit findCompatibleConduit(Message message) {
+        Conduit c = message.get(Conduit.class);
+        if (c == null
+            && message.getExchange() != null
+            && message.getExchange().getOutMessage() != null
+            && message.getExchange().getOutMessage() != message) {
+            c = message.getExchange().getOutMessage().get(Conduit.class);
+        }
+        if (c != null) {
+            return c;
+        }
+        ContextualBooleanGetter cbg = new ContextualBooleanGetter(message);
+        for (Conduit c2 : conduits) {
+            if (c2.getTarget() == null
+                || c2.getTarget().getAddress() == null
+                || c2.getTarget().getAddress().getValue() == null) {
+                continue;
+            }
+            String conduitAddress = c2.getTarget().getAddress().getValue();
+
+            EndpointInfo ei = endpoint.getEndpointInfo();
+            String actualAddress = ei.getAddress();
+
+            String messageAddress = (String)message.get(Message.ENDPOINT_ADDRESS);
+            if (messageAddress != null) {
+                actualAddress = messageAddress;
+            }
+
+            if (matchAddresses(conduitAddress, actualAddress, cbg)) {
+                return c2;
+            }
+        }
+        for (Conduit c2 : conduits) {
+            if (c2.getTarget() == null
+                || c2.getTarget().getAddress() == null
+                || c2.getTarget().getAddress().getValue() == null) {
+                return c2;
+            }
+        }
+        return null;
+    }
+
+    private boolean matchAddresses(String conduitAddress, String actualAddress, ContextualBooleanGetter cbg) {
+        if (conduitAddress.length() == actualAddress.length()) {
+            //let's be optimistic and try full comparison first, regardless of CONDUIT_COMPARE_FULL_URL value,
+            //which can be expensive to fetch; as a matter of fact, anyway, if the addresses fully match,
+            //their hosts also match
+            if (conduitAddress.equalsIgnoreCase(actualAddress)) {
+                return true;
+            }
+            return !cbg.isFullComparison() && matchAddressSubstrings(conduitAddress, actualAddress);
+        }
+        return !cbg.isFullComparison() && matchAddressSubstrings(conduitAddress, actualAddress);
+    }
+
+    //smart address substring comparison that tries to avoid building and comparing substrings unless strictly required
+    private boolean matchAddressSubstrings(String conduitAddress, String actualAddress) {
+        int idx = conduitAddress.indexOf(':');
+        if (idx == actualAddress.indexOf(':')) {
+            if (idx <= 0) {
+                return true;
+            }
+            return conduitAddress.substring(0, idx).equalsIgnoreCase(actualAddress.substring(0, idx));
+        }
+        //no possible match as for sure the substrings before idx will be different
+        return false;
+    }
+
+    private static final class ContextualBooleanGetter {
+        private Boolean value;
+        private final Message message;
+
+        ContextualBooleanGetter(Message message) {
+            this.message = message;
+        }
+
+        public boolean isFullComparison() {
+            if (value == null) {
+                value = MessageUtils.getContextualBoolean(message, CONDUIT_COMPARE_FULL_URL, false);
+            }
+            return value;
+        }
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/endpoint/ClientCallback.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/endpoint/ClientCallback.java
new file mode 100644
index 0000000000..467b5a800d
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/endpoint/ClientCallback.java
@@ -0,0 +1,166 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.endpoint;
+
+import java.util.Map;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.cxf.message.Message;
+
+/**
+ * Asynchronous callback object for calls to {@link Client#invoke(ClientCallback, String, Object...)}
+ * and related functions.
+ *
+ * The default behavior of this expects the following pattern:
+ * <ol>
+ * <li>ClientCallback cb = new ClientCallback();<>
+ * <li>client.invoke(cb, "someMethod", ....);</li>
+ * <li>cb.wait();</li>
+ * <li>// CXF calls notify on the callback object when the operation is complete.</li>
+ * </ol>
+ */
+public class ClientCallback implements Future<Object[]> {
+    protected final CompletableFuture<Object[]> delegate = new CompletableFuture<>();
+    protected Map<String, Object> context;
+    protected boolean started;
+
+    public ClientCallback() {
+    }
+
+    /**
+     * Called when a message is first received prior to any actions
+     * being applied to the message.   The InterceptorChain is setup so
+     * modifications to that can be done.
+     */
+    public void start(Message msg) {
+        started = true;
+    }
+
+    /**
+     * If the processing of the incoming message proceeds normally, this
+     * method is called with the response context values and the resulting objects.
+     *
+     * The default behavior just stores the objects and calls notifyAll to wake
+     * up threads waiting for the response.
+     *
+     * @param ctx
+     * @param res
+     */
+    public void handleResponse(Map<String, Object> ctx, Object[] res) {
+        context = ctx;
+        delegate.complete(res);
+
+        synchronized (this) {
+            notifyAll();
+        }
+    }
+
+    /**
+     * If processing of the incoming message results in an exception, this
+     * method is called with the resulting exception.
+     *
+     * The default behavior just stores the objects and calls notifyAll to wake
+     * up threads waiting for the response.
+     *
+     * @param ctx
+     * @param ex
+     */
+    public void handleException(Map<String, Object> ctx, Throwable ex) {
+        context = ctx;
+        delegate.completeExceptionally(ex);
+        
+        synchronized (this) {
+            notifyAll();
+        }
+    }
+
+
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        if (!started) {
+            delegate.cancel(mayInterruptIfRunning);
+            
+            synchronized (this) {
+                notifyAll();
+            }
+            
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * return the map of items returned from an operation.
+     * @return the response context
+     * @throws InterruptedException if the operation was cancelled.
+     * @throws ExecutionException if the operation resulted in a fault.
+     */
+    public Map<String, Object> getResponseContext() throws InterruptedException, ExecutionException {
+        synchronized (this) {
+            if (!delegate.isDone()) {
+                wait();
+            }
+        }
+        if (delegate.isCancelled()) {
+            throw new InterruptedException("Operation Cancelled");
+        }
+        if (delegate.isCompletedExceptionally()) {
+            delegate.get();
+        }
+        return context;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object[] get() throws InterruptedException, ExecutionException {
+        try {
+            return delegate.get();
+        } catch (final CancellationException ex) {
+            // Preserving the exception raised by former implementation
+            throw new InterruptedException("Operation has been cancelled");
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object[] get(long timeout, TimeUnit unit) throws InterruptedException, 
+            ExecutionException, TimeoutException {
+        try {
+            return delegate.get(timeout, unit);
+        } catch (final CancellationException ex) {
+            // Preserving the exception raised by former implementation
+            throw new InterruptedException("Operation has been cancelled");
+        }
+    }
+
+    public boolean isCancelled() {
+        return delegate.isCancelled();
+    }
+
+    public boolean isDone() {
+        return delegate.isDone();
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/endpoint/ClientImpl.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/endpoint/ClientImpl.java
new file mode 100644
index 0000000000..ffc07cc983
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/endpoint/ClientImpl.java
@@ -0,0 +1,1192 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.endpoint;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.Serializable;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.namespace.QName;
+import jakarta.xml.ws.handler.MessageContext;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.binding.Binding;
+import org.apache.cxf.common.classloader.ClassLoaderUtils;
+import org.apache.cxf.common.classloader.ClassLoaderUtils.ClassLoaderHolder;
+import org.apache.cxf.common.i18n.UncheckedException;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.PropertyUtils;
+import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.interceptor.AbstractBasicInterceptorProvider;
+import org.apache.cxf.interceptor.ClientOutFaultObserver;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.interceptor.Interceptor;
+import org.apache.cxf.interceptor.InterceptorChain;
+import org.apache.cxf.interceptor.InterceptorProvider;
+import org.apache.cxf.message.Exchange;
+import org.apache.cxf.message.ExchangeImpl;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageContentsList;
+import org.apache.cxf.message.MessageImpl;
+import org.apache.cxf.phase.PhaseChainCache;
+import org.apache.cxf.phase.PhaseInterceptorChain;
+import org.apache.cxf.phase.PhaseManager;
+import org.apache.cxf.service.Service;
+import org.apache.cxf.service.model.BindingInfo;
+import org.apache.cxf.service.model.BindingMessageInfo;
+import org.apache.cxf.service.model.BindingOperationInfo;
+import org.apache.cxf.service.model.EndpointInfo;
+import org.apache.cxf.service.model.MessageInfo;
+import org.apache.cxf.service.model.ServiceInfo;
+import org.apache.cxf.transport.Conduit;
+import org.apache.cxf.transport.MessageObserver;
+import org.apache.cxf.workqueue.SynchronousExecutor;
+
+public class ClientImpl
+    extends AbstractBasicInterceptorProvider
+    implements Client, Retryable, MessageObserver {
+
+    public static final String THREAD_LOCAL_REQUEST_CONTEXT = "thread.local.request.context";
+    /**
+     * When a synchronous request/response invoke is done using an asynchronous transport mechanism,
+     * this is the timeout used for waiting for the response.  Default is 60 seconds.
+     */
+    public static final String SYNC_TIMEOUT = "cxf.synchronous.timeout";
+
+    public static final String FINISHED = "exchange.finished";
+
+    private static final Logger LOG = LogUtils.getL7dLogger(ClientImpl.class);
+
+    protected Bus bus;
+    protected ConduitSelector conduitSelector;
+    protected ClientOutFaultObserver outFaultObserver;
+    protected int synchronousTimeout = 60000; // default 60 second timeout
+
+    protected PhaseChainCache outboundChainCache = new PhaseChainCache();
+    protected PhaseChainCache inboundChainCache = new PhaseChainCache();
+
+    protected Map<String, Object> currentRequestContext = new ConcurrentHashMap<>(8, 0.75f, 4);
+    protected Thread latestContextThread;
+    protected Map<Thread, EchoContext> requestContext
+        = Collections.synchronizedMap(new WeakHashMap<Thread, EchoContext>());
+
+    protected Map<Thread, ResponseContext> responseContext
+        = Collections.synchronizedMap(new WeakHashMap<Thread, ResponseContext>());
+
+    protected Executor executor;
+
+    public ClientImpl(Bus b, Endpoint e) {
+        this(b, e, (ConduitSelector)null);
+    }
+
+    public ClientImpl(Bus b, Endpoint e, Conduit c) {
+        this(b, e, new PreexistingConduitSelector(c));
+    }
+
+    public ClientImpl(Bus b, Endpoint e, ConduitSelector sc) {
+        bus = b;
+        outFaultObserver = new ClientOutFaultObserver(bus);
+        getConduitSelector(sc).setEndpoint(e);
+        notifyLifecycleManager();
+    }
+
+    /**
+     * Create a Client that uses a specific EndpointImpl.
+     * @param bus
+     * @param svc
+     * @param port
+     * @param endpointImplFactory
+     */
+    public ClientImpl(Bus bus, Service svc, QName port,
+                      EndpointImplFactory endpointImplFactory) {
+        this.bus = bus;
+        outFaultObserver = new ClientOutFaultObserver(bus);
+        EndpointInfo epfo = findEndpoint(svc, port);
+
+        try {
+            if (endpointImplFactory != null) {
+                getConduitSelector().setEndpoint(endpointImplFactory.newEndpointImpl(bus, svc, epfo));
+            } else {
+                getConduitSelector().setEndpoint(new EndpointImpl(bus, svc, epfo));
+            }
+        } catch (EndpointException epex) {
+            throw new IllegalStateException("Unable to create endpoint: " + epex.getMessage(), epex);
+        }
+        notifyLifecycleManager();
+    }
+
+    public Bus getBus() {
+        return bus;
+    }
+
+    public void destroy() {
+        if (bus == null) {
+            return;
+        }
+        if (getEndpoint() != null) {
+            for (Closeable c : getEndpoint().getCleanupHooks()) {
+                try {
+                    c.close();
+                } catch (IOException e) {
+                    //ignore
+                }
+            }
+        }
+        ClientLifeCycleManager mgr = bus.getExtension(ClientLifeCycleManager.class);
+        if (null != mgr) {
+            mgr.clientDestroyed(this);
+        }
+
+        if (conduitSelector != null) {
+            if (conduitSelector instanceof Closeable) {
+                try {
+                    ((Closeable)conduitSelector).close();
+                } catch (IOException e) {
+                    //ignore, we're destroying anyway
+                }
+            } else {
+                getConduit().close();
+            }
+        }
+
+        bus = null;
+        conduitSelector = null;
+        outFaultObserver = null;
+        outboundChainCache = null;
+        inboundChainCache = null;
+
+        currentRequestContext = null;
+        requestContext.clear();
+        requestContext = null;
+        responseContext.clear();
+        responseContext = null;
+        executor = null;
+    }
+
+    private void notifyLifecycleManager() {
+        ClientLifeCycleManager mgr = bus.getExtension(ClientLifeCycleManager.class);
+        if (null != mgr) {
+            mgr.clientCreated(this);
+        }
+    }
+
+    private EndpointInfo findEndpoint(Service svc, QName port) {
+        if (port != null) {
+            EndpointInfo epfo = svc.getEndpointInfo(port);
+            if (epfo == null) {
+                throw new IllegalArgumentException("The service " + svc.getName()
+                                                   + " does not have an endpoint " + port + ".");
+            }
+            return epfo;
+        }
+        
+        for (ServiceInfo svcfo : svc.getServiceInfos()) {
+            for (EndpointInfo e : svcfo.getEndpoints()) {
+                BindingInfo bfo = e.getBinding();
+                String bid = bfo.getBindingId();
+                if ("http://schemas.xmlsoap.org/wsdl/soap/".equals(bid)
+                    || "http://schemas.xmlsoap.org/wsdl/soap12/".equals(bid)) {
+                    for (Object o : bfo.getExtensors().get()) {
+                        try {
+                            String s = (String)o.getClass().getMethod("getTransportURI").invoke(o);
+                            if (s != null && s.endsWith("http")) {
+                                return e;
+                            }
+                        } catch (Throwable t) {
+                            //ignore
+                        }
+                    }
+                }
+            }
+        }
+        throw new UnsupportedOperationException(
+             "Only document-style SOAP 1.1 and 1.2 http are supported "
+             + "for auto-selection of endpoint; none were found.");
+    }
+
+    public Endpoint getEndpoint() {
+        return getConduitSelector().getEndpoint();
+    }
+
+    public void releaseThreadContexts() {
+        final Thread t = Thread.currentThread();
+        requestContext.remove(t);
+        responseContext.remove(t);
+    }
+
+    @Override
+    public Contexts getContexts() {
+        return new Contexts() {
+            @Override
+            public void close() throws Exception {
+                releaseThreadContexts();
+            }
+            @Override
+            public Map<String, Object> getRequestContext() {
+                return ClientImpl.this.getRequestContext();
+            }
+            @Override
+            public Map<String, Object> getResponseContext() {
+                return ClientImpl.this.getResponseContext();
+            }
+        };
+    }
+
+    public Map<String, Object> getRequestContext() {
+        if (isThreadLocalRequestContext()) {
+            final Thread t = Thread.currentThread();
+            requestContext.computeIfAbsent(t, k -> new EchoContext(currentRequestContext));
+            latestContextThread = t;
+            return requestContext.get(t);
+        }
+        return currentRequestContext;
+    }
+    public Map<String, Object> getResponseContext() {
+        if (!responseContext.containsKey(Thread.currentThread())) {
+            final Thread t = Thread.currentThread();
+            responseContext.put(t, new ResponseContext(responseContext));
+        }
+        return responseContext.get(Thread.currentThread());
+    }
+    protected Map<String, Object> setResponseContext(Map<String, Object> ctx) {
+        if (ctx instanceof ResponseContext) {
+            ResponseContext c = (ResponseContext)ctx;
+            responseContext.put(Thread.currentThread(), c);
+            return c;
+        }
+        ResponseContext c = new ResponseContext(ctx, responseContext);
+        responseContext.put(Thread.currentThread(), c);
+        return c;
+    }
+    public boolean isThreadLocalRequestContext() {
+        Object o = currentRequestContext.get(THREAD_LOCAL_REQUEST_CONTEXT);
+        if (o != null) {
+            final boolean local;
+            if (o instanceof Boolean) {
+                local = ((Boolean)o).booleanValue();
+            } else {
+                local = Boolean.parseBoolean(o.toString());
+            }
+            return local;
+        }
+        return false;
+    }
+    public void setThreadLocalRequestContext(boolean b) {
+        currentRequestContext.put(THREAD_LOCAL_REQUEST_CONTEXT, b);
+    }
+
+
+    public Object[] invoke(BindingOperationInfo oi, Object... params) throws Exception {
+        return invoke(oi, params, null);
+    }
+
+    public Object[] invoke(String operationName, Object... params) throws Exception {
+        QName q = new QName(getEndpoint().getService().getName().getNamespaceURI(), operationName);
+
+        return invoke(q, params);
+    }
+
+    public Object[] invoke(QName operationName, Object... params) throws Exception {
+        BindingOperationInfo op = getEndpoint().getEndpointInfo().getBinding().getOperation(operationName);
+        if (op == null) {
+            throw new UncheckedException(
+                new org.apache.cxf.common.i18n.Message("NO_OPERATION", LOG, operationName));
+        }
+
+        if (op.isUnwrappedCapable()) {
+            op = op.getUnwrappedOperation();
+        }
+
+        return invoke(op, params);
+    }
+
+    public Object[] invokeWrapped(String operationName, Object... params) throws Exception {
+        QName q = new QName(getEndpoint().getService().getName().getNamespaceURI(), operationName);
+
+        return invokeWrapped(q, params);
+    }
+
+    public Object[] invokeWrapped(QName operationName, Object... params) throws Exception {
+        BindingOperationInfo op = getEndpoint().getEndpointInfo().getBinding().getOperation(operationName);
+        if (op == null) {
+            throw new UncheckedException(
+                new org.apache.cxf.common.i18n.Message("NO_OPERATION", LOG, operationName));
+        }
+        return invoke(op, params);
+    }
+
+    public Object[] invoke(BindingOperationInfo oi,
+                           Object[] params,
+                           Exchange exchange) throws Exception {
+        Map<String, Object> context = new HashMap<>();
+        return invoke(oi, params, context, exchange);
+    }
+    public Object[] invoke(BindingOperationInfo oi,
+                           Object[] params,
+                           Map<String, Object> context) throws Exception {
+        return invoke(oi, params, context, (Exchange)null);
+    }
+
+    public void invoke(ClientCallback callback,
+                       String operationName,
+                       Object... params) throws Exception {
+        QName q = new QName(getEndpoint().getService().getName().getNamespaceURI(), operationName);
+        invoke(callback, q, params);
+    }
+
+    public void invoke(ClientCallback callback,
+                       QName operationName,
+                       Object... params) throws Exception {
+        BindingOperationInfo op = getEndpoint().getEndpointInfo().getBinding().getOperation(operationName);
+        if (op == null) {
+            throw new UncheckedException(
+                new org.apache.cxf.common.i18n.Message("NO_OPERATION", LOG, operationName));
+        }
+
+        if (op.isUnwrappedCapable()) {
+            op = op.getUnwrappedOperation();
+        }
+
+        invoke(callback, op, params);
+    }
+
+
+    public void invokeWrapped(ClientCallback callback,
+                              String operationName,
+                              Object... params)
+        throws Exception {
+        QName q = new QName(getEndpoint().getService().getName().getNamespaceURI(), operationName);
+        invokeWrapped(callback, q, params);
+    }
+
+    public void invokeWrapped(ClientCallback callback,
+                              QName operationName,
+                              Object... params)
+        throws Exception {
+        BindingOperationInfo op = getEndpoint().getEndpointInfo().getBinding().getOperation(operationName);
+        if (op == null) {
+            throw new UncheckedException(
+                new org.apache.cxf.common.i18n.Message("NO_OPERATION", LOG, operationName));
+        }
+        invoke(callback, op, params);
+    }
+
+
+    public void invoke(ClientCallback callback,
+                       BindingOperationInfo oi,
+                       Object... params) throws Exception {
+        invoke(callback, oi, params, null, null);
+    }
+
+    public void invoke(ClientCallback callback,
+                       BindingOperationInfo oi,
+                       Object[] params,
+                       Map<String, Object> context) throws Exception {
+        invoke(callback, oi, params, context, null);
+    }
+
+    public void invoke(ClientCallback callback,
+                       BindingOperationInfo oi,
+                       Object[] params,
+                       Exchange exchange) throws Exception {
+        invoke(callback, oi, params, null, exchange);
+    }
+
+    public void invoke(ClientCallback callback,
+                       BindingOperationInfo oi,
+                       Object[] params,
+                       Map<String, Object> context,
+                       Exchange exchange) throws Exception {
+        doInvoke(callback, oi, params, context, exchange);
+    }
+
+    public Object[] invoke(BindingOperationInfo oi,
+                           Object[] params,
+                           Map<String, Object> context,
+                           Exchange exchange) throws Exception {
+        return doInvoke(null, oi, params, context, exchange);
+    }
+
+    private Object[] doInvoke(final ClientCallback callback,
+                              BindingOperationInfo oi,
+                              Object[] params,
+                              Map<String, Object> context,
+                              Exchange exchange) throws Exception {
+        Bus origBus = BusFactory.getAndSetThreadDefaultBus(bus);
+        ClassLoaderHolder origLoader = null;
+        Map<String, Object> resContext = null;
+        try {
+            ClassLoader loader = bus.getExtension(ClassLoader.class);
+            if (loader != null) {
+                origLoader = ClassLoaderUtils.setThreadContextClassloader(loader);
+            }
+            if (exchange == null) {
+                exchange = new ExchangeImpl();
+            }
+            exchange.setSynchronous(callback == null);
+            Endpoint endpoint = getEndpoint();
+            if (LOG.isLoggable(Level.FINE)) {
+                LOG.fine("Invoke, operation info: " + oi + ", params: " + Arrays.toString(params));
+            }
+            Message message = endpoint.getBinding().createMessage();
+
+            // Make sure INVOCATION CONTEXT, REQUEST_CONTEXT and RESPONSE_CONTEXT are present
+            // on message
+            if (context == null) {
+                context = new HashMap<>();
+            }
+            Map<String, Object> reqContext = CastUtils.cast((Map<?, ?>)context.get(REQUEST_CONTEXT));
+            resContext = CastUtils.cast((Map<?, ?>)context.get(RESPONSE_CONTEXT));
+            if (reqContext == null) {
+                reqContext = new HashMap<>(getRequestContext());
+                context.put(REQUEST_CONTEXT, reqContext);
+            }
+            if (resContext == null) {
+                resContext = new ResponseContext(responseContext);
+                context.put(RESPONSE_CONTEXT, resContext);
+            }
+
+            message.put(Message.INVOCATION_CONTEXT, context);
+            setContext(reqContext, message);
+            exchange.putAll(reqContext);
+
+            setParameters(params, message);
+
+            if (null != oi) {
+                exchange.setOneWay(oi.getOutput() == null);
+            }
+
+            exchange.setOutMessage(message);
+            exchange.put(ClientCallback.class, callback);
+
+            setOutMessageProperties(message, oi);
+            setExchangeProperties(exchange, endpoint, oi);
+
+            PhaseInterceptorChain chain = setupInterceptorChain(endpoint);
+            message.setInterceptorChain(chain);
+            if (callback == null) {
+                chain.setFaultObserver(outFaultObserver);
+            } else {
+                // We need to wrap the outFaultObserver if the callback is not null
+                // calling the conduitSelector.complete to make sure the fail over feature works
+                chain.setFaultObserver(new MessageObserver() {
+                    public void onMessage(Message message) {
+                        Exception ex = message.getContent(Exception.class);
+                        if (ex != null) {
+                            completeExchange(message.getExchange());
+                            if (message.getContent(Exception.class) == null) {
+                                // handle the right response
+                                Message inMsg = message.getExchange().getInMessage();
+                                Map<String, Object> ctx = responseContext.get(Thread.currentThread());
+                                List<Object> resList = CastUtils.cast(inMsg.getContent(List.class));
+                                Object[] result = resList == null ? null : resList.toArray();
+                                callback.handleResponse(ctx, result);
+                                return;
+                            }
+                        }
+                        outFaultObserver.onMessage(message);
+                    }
+                });
+            }
+            prepareConduitSelector(message);
+
+            // add additional interceptors and such
+            modifyChain(chain, message, false);
+            try {
+                chain.doIntercept(message);
+            } catch (Fault fault) {
+                enrichFault(fault);
+                throw fault;
+            }
+
+            if (callback != null) {
+                return null;
+            }
+            return processResult(message, exchange, oi, resContext);
+        } finally {
+            //ensure ResponseContext has HTTP RESPONSE CODE
+            if (null != exchange) {
+                Integer responseCode = (Integer)exchange.get(Message.RESPONSE_CODE);
+                resContext.put(MessageContext.HTTP_RESPONSE_CODE, responseCode);
+                resContext.put(org.apache.cxf.message.Message.RESPONSE_CODE, responseCode);
+                setResponseContext(resContext);
+            }
+            if (origLoader != null) {
+                origLoader.reset();
+            }
+            if (origBus != bus) {
+                BusFactory.setThreadDefaultBus(origBus);
+            }
+        }
+    }
+
+    private void completeExchange(Exchange exchange) {
+        getConduitSelector().complete(exchange);
+    }
+
+    /**
+     * TODO This is SOAP specific code and should not be in cxf core
+     * @param fault
+     */
+    private void enrichFault(Fault fault) {
+        if (fault.getCause().getCause() instanceof IOException
+                || fault.getCause() instanceof IOException) {
+            String soap11NS = "http://schemas.xmlsoap.org/soap/envelope/";
+            String soap12NS = "http://www.w3.org/2003/05/soap-envelope";
+            QName faultCode = fault.getFaultCode();
+            //for SoapFault, if it's underlying cause is IOException,
+            //it means something like server is down or can't create
+            //connection, according to soap spec we should set fault as
+            //Server Fault
+            if (faultCode.getNamespaceURI().equals(
+                    soap11NS)
+                    && "Client".equals(faultCode.getLocalPart())) {
+                faultCode = new QName(soap11NS, "Server");
+                fault.setFaultCode(faultCode);
+            }
+            if (faultCode.getNamespaceURI().equals(
+                    soap12NS)
+                    && "Sender".equals(faultCode.getLocalPart())) {
+                faultCode = new QName(soap12NS, "Receiver");
+                fault.setFaultCode(faultCode);
+            }
+        }
+    }
+
+    protected Object[] processResult(Message message,
+                                   Exchange exchange,
+                                   BindingOperationInfo oi,
+                                   Map<String, Object> resContext) throws Exception {
+        Exception ex = null;
+        // Check to see if there is a Fault from the outgoing chain if it's an out Message
+        if (!message.get(Message.INBOUND_MESSAGE).equals(Boolean.TRUE)) {
+            ex = message.getContent(Exception.class);
+        }
+        boolean mepCompleteCalled = false;
+        if (ex != null) {
+            completeExchange(exchange);
+            mepCompleteCalled = true;
+            if (message.getContent(Exception.class) != null) {
+                throw ex;
+            }
+        }
+        ex = message.getExchange().get(Exception.class);
+        if (ex != null) {
+            if (!mepCompleteCalled) {
+                completeExchange(exchange);
+            }
+            throw ex;
+        }
+
+        //REVISIT
+        // - use a protocol neutral no-content marker instead of 202?
+        // - move the decoupled destination property name into api
+        Integer responseCode = (Integer)exchange.get(Message.RESPONSE_CODE);
+        if (null != responseCode && 202 == responseCode) {
+            Endpoint ep = exchange.getEndpoint();
+            if (null != ep && null != ep.getEndpointInfo() && null == ep.getEndpointInfo().
+                getProperty("org.apache.cxf.ws.addressing.MAPAggregator.decoupledDestination")) {
+                return null;
+            }
+        }
+
+        // Wait for a response if we need to
+        if (oi != null && !oi.getOperationInfo().isOneWay()) {
+            waitResponse(exchange);
+        }
+
+        // leave the input stream open for the caller
+        Boolean keepConduitAlive = (Boolean)exchange.get(Client.KEEP_CONDUIT_ALIVE);
+        if (keepConduitAlive == null || !keepConduitAlive) {
+            completeExchange(exchange);
+        }
+
+        // Grab the response objects if there are any
+        List<Object> resList = null;
+        Message inMsg = exchange.getInMessage();
+        if (inMsg != null) {
+            if (null != resContext) {
+                resContext.putAll(inMsg);
+                // remove the recursive reference if present
+                resContext.remove(Message.INVOCATION_CONTEXT);
+                setResponseContext(resContext);
+            }
+            resList = CastUtils.cast(inMsg.getContent(List.class));
+        }
+
+        // check for an incoming fault
+        ex = getException(exchange);
+
+        if (ex != null) {
+            throw ex;
+        }
+
+        if (resList == null   
+            && oi != null && !oi.getOperationInfo().isOneWay()) {
+            
+            BindingOperationInfo boi = oi;
+            if (boi.isUnwrapped()) {
+                boi = boi.getWrappedOperation();
+            }
+            if (!boi.getOutput().getMessageParts().isEmpty()) {
+                //we were supposed to get some output, but didn't.
+                throw new IllegalEmptyResponseException("Response message did not contain proper response data."
+                    + " Expected: " + boi.getOutput().getMessageParts().get(0).getConcreteName());
+            }
+        }
+        if (resList != null) {
+            return resList.toArray();
+        }
+
+        return null;
+    }
+    protected Exception getException(Exchange exchange) {
+        if (exchange.getInFaultMessage() != null) {
+            return exchange.getInFaultMessage().getContent(Exception.class);
+        } else if (exchange.getOutFaultMessage() != null) {
+            return exchange.getOutFaultMessage().getContent(Exception.class);
+        } else if (exchange.getInMessage() != null) {
+            return exchange.getInMessage().getContent(Exception.class);
+        }
+        return null;
+    }
+
+    protected void setContext(Map<String, Object> ctx, Message message) {
+        if (ctx != null) {
+            message.putAll(ctx);
+            if (LOG.isLoggable(Level.FINE)) {
+                LOG.fine("set requestContext to message be" + ctx);
+            }
+        }
+    }
+
+    protected void waitResponse(Exchange exchange) throws IOException {
+        synchronized (exchange) {
+            long remaining = synchronousTimeout;
+            Long o = PropertyUtils.getLong(exchange.getOutMessage(), SYNC_TIMEOUT);
+            if (o != null) {
+                remaining = o;
+            }
+            while (!Boolean.TRUE.equals(exchange.get(FINISHED)) && remaining > 0) {
+                long start = System.currentTimeMillis();
+                try {
+                    exchange.wait(remaining);
+                } catch (InterruptedException ex) {
+                    // ignore
+                }
+                long end = System.currentTimeMillis();
+                remaining -= (int)(end - start);
+            }
+            if (!Boolean.TRUE.equals(exchange.get(FINISHED))) {
+                LogUtils.log(LOG, Level.WARNING, "RESPONSE_TIMEOUT",
+                    exchange.getBindingOperationInfo().getOperationInfo().getName().toString());
+                String msg = new org.apache.cxf.common.i18n.Message("RESPONSE_TIMEOUT", LOG, exchange
+                    .getBindingOperationInfo().getOperationInfo().getName().toString()).toString();
+                throw new IOException(msg);
+            }
+        }
+    }
+
+    protected void setParameters(Object[] params, Message message) {
+        MessageContentsList contents = new MessageContentsList(params);
+        message.setContent(List.class, contents);
+    }
+
+    public void onMessage(Message message) {
+        if (bus == null) {
+            throw new IllegalStateException("Message received on a Client that has been closed or destroyed.");
+        }
+        Endpoint endpoint = message.getExchange().getEndpoint();
+        if (endpoint == null) {
+            // in this case correlation will occur outside the transport,
+            // however there's a possibility that the endpoint may have been
+            // rebased in the meantime, so that the response will be mediated
+            // via a set of in interceptors provided by a *different* endpoint
+            //
+            endpoint = getConduitSelector().getEndpoint();
+            message.getExchange().put(Endpoint.class, endpoint);
+        }
+        message = endpoint.getBinding().createMessage(message);
+        message.getExchange().setInMessage(message);
+        message.put(Message.REQUESTOR_ROLE, Boolean.TRUE);
+        message.put(Message.INBOUND_MESSAGE, Boolean.TRUE);
+        PhaseManager pm = bus.getExtension(PhaseManager.class);
+
+        List<Interceptor<? extends Message>> i1 = bus.getInInterceptors();
+        if (LOG.isLoggable(Level.FINE)) {
+            LOG.fine("Interceptors contributed by bus: " + i1);
+        }
+        List<Interceptor<? extends Message>> i2 = getInInterceptors();
+        if (LOG.isLoggable(Level.FINE)) {
+            LOG.fine("Interceptors contributed by client: " + i2);
+        }
+        List<Interceptor<? extends Message>> i3 = endpoint.getInInterceptors();
+        if (LOG.isLoggable(Level.FINE)) {
+            LOG.fine("Interceptors contributed by endpoint: " + i3);
+        }
+        List<Interceptor<? extends Message>> i4 = endpoint.getBinding().getInInterceptors();
+        if (LOG.isLoggable(Level.FINE)) {
+            LOG.fine("Interceptors contributed by binding: " + i4);
+        }
+
+        PhaseInterceptorChain chain;
+        if (endpoint.getService().getDataBinding() instanceof InterceptorProvider) {
+            InterceptorProvider p = (InterceptorProvider)endpoint.getService().getDataBinding();
+            if (LOG.isLoggable(Level.FINE)) {
+                LOG.fine("Interceptors contributed by databinding: " + p.getInInterceptors());
+            }
+            chain = inboundChainCache.get(pm.getInPhases(), i1, i2, i3, i4,
+                                          p.getInInterceptors());
+        } else {
+            chain = inboundChainCache.get(pm.getInPhases(), i1, i2, i3, i4);
+        }
+        message.setInterceptorChain(chain);
+
+        chain.setFaultObserver(outFaultObserver);
+        modifyChain(chain, message, true);
+        modifyChain(chain, message.getExchange().getOutMessage(), true);
+
+        Bus origBus = BusFactory.getAndSetThreadDefaultBus(bus);
+        // execute chain
+        ClientCallback callback = message.getExchange().get(ClientCallback.class);
+        try {
+            if (callback != null) {
+                if (callback.isCancelled()) {
+                    completeExchange(message.getExchange());
+                    return;
+                }
+                callback.start(message);
+            }
+
+            String startingAfterInterceptorID = (String) message.get(
+                InterceptorChain.STARTING_AFTER_INTERCEPTOR_ID);
+            String startingInterceptorID = (String) message.get(
+                InterceptorChain.STARTING_AT_INTERCEPTOR_ID);
+            if (startingAfterInterceptorID != null) {
+                chain.doInterceptStartingAfter(message, startingAfterInterceptorID);
+            } else if (startingInterceptorID != null) {
+                chain.doInterceptStartingAt(message, startingInterceptorID);
+            } else if (message.getContent(Exception.class) != null) {
+                outFaultObserver.onMessage(message);
+            } else {
+                callback = message.getExchange().get(ClientCallback.class);
+
+                if (callback != null && !isPartialResponse(message)) {
+                    try {
+                        chain.doIntercept(message);
+                    } catch (Throwable error) {
+                        //so that asyn callback handler get chance to
+                        //handle non-runtime exceptions
+                        message.getExchange().setInMessage(message);
+                        Map<String, Object> resCtx = CastUtils
+                                .cast((Map<?, ?>) message.getExchange()
+                                        .getOutMessage().get(
+                                                Message.INVOCATION_CONTEXT));
+                        resCtx = CastUtils.cast((Map<?, ?>) resCtx
+                                .get(RESPONSE_CONTEXT));
+                        if (resCtx != null) {
+                            setResponseContext(resCtx);
+                        }
+                        // remove callback so that it won't be invoked twice
+                        callback = message.getExchange().remove(ClientCallback.class);
+                        if (callback != null) {
+                            callback.handleException(resCtx, error);
+                        }
+                    }
+                } else {
+                    chain.doIntercept(message);
+                }
+
+            }
+
+            callback = message.getExchange().get(ClientCallback.class);
+            if (callback == null || isPartialResponse(message)) {
+                return;
+            }
+
+            // remove callback so that it won't be invoked twice
+            callback = message.getExchange().remove(ClientCallback.class);
+            if (callback != null) {
+                message.getExchange().setInMessage(message);
+                Map<String, Object> resCtx = CastUtils.cast((Map<?, ?>)message
+                                                                .getExchange()
+                                                                .getOutMessage()
+                                                                .get(Message.INVOCATION_CONTEXT));
+                resCtx = CastUtils.cast((Map<?, ?>)resCtx.get(RESPONSE_CONTEXT));
+                if (resCtx != null && responseContext != null) {
+                    setResponseContext(resCtx);
+                }
+                try {
+                    Object[] obj = processResult(message, message.getExchange(),
+                                                 null, resCtx);
+
+                    callback.handleResponse(resCtx, obj);
+                } catch (Throwable ex) {
+                    callback.handleException(resCtx, ex);
+                }
+            }
+        } finally {
+            if (origBus != bus) {
+                BusFactory.setThreadDefaultBus(origBus);
+            }
+            synchronized (message.getExchange()) {
+                if (!isPartialResponse(message)
+                    || message.getContent(Exception.class) != null) {
+                    message.getExchange().put(FINISHED, Boolean.TRUE);
+                    message.getExchange().setInMessage(message);
+                    message.getExchange().notifyAll();
+                }
+            }
+        }
+    }
+
+    public Conduit getConduit() {
+        Message message = new MessageImpl();
+        Exchange exchange = new ExchangeImpl();
+        message.setExchange(exchange);
+        message.putAll(getRequestContext());
+        setExchangeProperties(exchange, getEndpoint(), null);
+        return getConduitSelector().selectConduit(message);
+    }
+
+    protected void prepareConduitSelector(Message message) {
+        getConduitSelector().prepare(message);
+        message.getExchange().put(ConduitSelector.class, getConduitSelector());
+    }
+
+    protected void setOutMessageProperties(Message message, BindingOperationInfo boi) {
+        message.put(Message.REQUESTOR_ROLE, Boolean.TRUE);
+        message.put(Message.INBOUND_MESSAGE, Boolean.FALSE);
+        if (null != boi) {
+            message.put(BindingMessageInfo.class, boi.getInput());
+            message.put(MessageInfo.class, boi.getOperationInfo().getInput());
+        }
+    }
+
+    protected void setExchangeProperties(Exchange exchange,
+                                         Endpoint endpoint,
+                                         BindingOperationInfo boi) {
+        if (endpoint != null) {
+            exchange.put(Endpoint.class, endpoint);
+            exchange.put(Service.class, endpoint.getService());
+            exchange.put(Binding.class, endpoint.getBinding());
+        }
+        if (boi != null) {
+            exchange.put(BindingOperationInfo.class, boi);
+        }
+
+        if (exchange.isSynchronous() || executor == null) {
+            exchange.put(MessageObserver.class, this);
+        } else {
+            exchange.put(Executor.class, executor);
+            exchange.put(MessageObserver.class, new MessageObserver() {
+                public void onMessage(final Message message) {
+                    if (!message.getExchange()
+                        .containsKey(Executor.class.getName() + ".USING_SPECIFIED")) {
+
+                        executor.execute(new Runnable() {
+                            public void run() {
+                                ClientImpl.this.onMessage(message);
+                            }
+                        });
+                    } else {
+                        ClientImpl.this.onMessage(message);
+                    }
+                }
+            });
+        }
+        exchange.put(Retryable.class, this);
+        exchange.put(Client.class, this);
+        exchange.put(Bus.class, bus);
+
+        if (endpoint != null) {
+            EndpointInfo endpointInfo = endpoint.getEndpointInfo();
+            if (boi != null) {
+                exchange.put(Message.WSDL_OPERATION, boi.getName());
+            }
+
+            QName serviceQName = endpointInfo.getService().getName();
+            exchange.put(Message.WSDL_SERVICE, serviceQName);
+
+            QName interfaceQName = endpointInfo.getService().getInterface().getName();
+            exchange.put(Message.WSDL_INTERFACE, interfaceQName);
+
+            QName portQName = endpointInfo.getName();
+            exchange.put(Message.WSDL_PORT, portQName);
+            URI wsdlDescription = endpointInfo.getProperty("URI", URI.class);
+            if (wsdlDescription == null) {
+                String address = endpointInfo.getAddress();
+                try {
+                    wsdlDescription = new URI(address + "?wsdl");
+                } catch (URISyntaxException e) {
+                    // do nothing
+                }
+                endpointInfo.setProperty("URI", wsdlDescription);
+            }
+            exchange.put(Message.WSDL_DESCRIPTION, wsdlDescription);
+        }
+    }
+
+    protected PhaseInterceptorChain setupInterceptorChain(Endpoint endpoint) {
+
+        PhaseManager pm = bus.getExtension(PhaseManager.class);
+
+        List<Interceptor<? extends Message>> i1 = bus.getOutInterceptors();
+        if (LOG.isLoggable(Level.FINE)) {
+            LOG.fine("Interceptors contributed by bus: " + i1);
+        }
+        List<Interceptor<? extends Message>> i2 = getOutInterceptors();
+        if (LOG.isLoggable(Level.FINE)) {
+            LOG.fine("Interceptors contributed by client: " + i2);
+        }
+        List<Interceptor<? extends Message>> i3 = endpoint.getOutInterceptors();
+        if (LOG.isLoggable(Level.FINE)) {
+            LOG.fine("Interceptors contributed by endpoint: " + i3);
+        }
+        List<Interceptor<? extends Message>> i4 = endpoint.getBinding().getOutInterceptors();
+        if (LOG.isLoggable(Level.FINE)) {
+            LOG.fine("Interceptors contributed by binding: " + i4);
+        }
+        List<Interceptor<? extends Message>> i5 = null;
+        if (endpoint.getService().getDataBinding() instanceof InterceptorProvider) {
+            i5 = ((InterceptorProvider)endpoint.getService().getDataBinding()).getOutInterceptors();
+            if (LOG.isLoggable(Level.FINE)) {
+                LOG.fine("Interceptors contributed by databinding: " + i5);
+            }
+        }
+        if (i5 != null) {
+            return outboundChainCache.get(pm.getOutPhases(), i1, i2, i3, i4, i5);
+        }
+        return outboundChainCache.get(pm.getOutPhases(), i1, i2, i3, i4);
+    }
+
+    protected void modifyChain(InterceptorChain chain, Message ctx, boolean in) {
+        if (ctx == null) {
+            return;
+        }
+        Collection<InterceptorProvider> providers
+            = CastUtils.cast((Collection<?>)ctx.get(Message.INTERCEPTOR_PROVIDERS));
+        if (providers != null) {
+            for (InterceptorProvider p : providers) {
+                if (in) {
+                    chain.add(p.getInInterceptors());
+                } else {
+                    chain.add(p.getOutInterceptors());
+                }
+            }
+        }
+        String key = in ? Message.IN_INTERCEPTORS : Message.OUT_INTERCEPTORS;
+        Collection<Interceptor<? extends Message>> is
+            = CastUtils.cast((Collection<?>)ctx.get(key));
+        if (is != null) {
+            chain.add(is);
+        }
+    }
+
+    protected void setEndpoint(Endpoint e) {
+        getConduitSelector().setEndpoint(e);
+    }
+
+    public int getSynchronousTimeout() {
+        return synchronousTimeout;
+    }
+
+    public void setSynchronousTimeout(int synchronousTimeout) {
+        this.synchronousTimeout = synchronousTimeout;
+    }
+
+    public final ConduitSelector getConduitSelector() {
+        return getConduitSelector(null);
+    }
+
+    protected final ConduitSelector getConduitSelector(
+        ConduitSelector override
+    ) {
+        if (null == conduitSelector) {
+            setConduitSelector(override);
+        }
+        return conduitSelector;
+    }
+
+    public final synchronized void setConduitSelector(ConduitSelector selector) {
+        conduitSelector = selector == null ? new UpfrontConduitSelector() : selector;
+    }
+
+    private boolean isPartialResponse(Message in) {
+        return Boolean.TRUE.equals(in.get(Message.PARTIAL_RESPONSE_MESSAGE));
+    }
+
+    @Override
+    public void close() throws Exception {
+        destroy();
+    }
+
+
+    public class EchoContext extends ConcurrentHashMap<String, Object> {
+        private static final long serialVersionUID = 1L;
+        public EchoContext(Map<String, Object> sharedMap) {
+            super(8, 0.75f, 4);
+            putAll(sharedMap);
+        }
+
+        public void reload() {
+            super.clear();
+            super.putAll(requestContext.get(latestContextThread));
+        }
+        
+        @Override
+        public void clear() {
+            super.clear();
+            try {
+                for (Map.Entry<Thread, EchoContext> ent : requestContext.entrySet()) {
+                    if (ent.getValue() == this) {
+                        requestContext.remove(ent.getKey());
+                        return;
+                    }
+                }
+            } catch (Throwable t) {
+                //ignore
+            }
+        }
+    }
+
+    /**
+     * Class to handle the response contexts.   The clear is overloaded to remove
+     * this context from the threadLocal caches in the ClientImpl
+     */
+    static class ResponseContext implements Map<String, Object>, Serializable {
+        private static final long serialVersionUID = 2L;
+        final Map<String, Object> wrapped;
+        final Map<Thread, ResponseContext> responseContext;
+        
+        ResponseContext(Map<String, Object> origMap, Map<Thread, ResponseContext> rc) {
+            wrapped = origMap;
+            responseContext = rc;
+        }
+
+        ResponseContext(Map<Thread, ResponseContext> rc) {
+            wrapped = new HashMap<>();
+            responseContext = rc;
+        }
+
+        @Override
+        public void clear() {
+            wrapped.clear();
+            try {
+                for (Map.Entry<Thread, ResponseContext> ent : responseContext.entrySet()) {
+                    if (ent.getValue() == this) {
+                        responseContext.remove(ent.getKey());
+                        return;
+                    }
+                }
+            } catch (Throwable t) {
+                //ignore
+            }
+        }
+
+        @Override
+        public int size() {
+            return wrapped.size();
+        }
+        @Override
+        public boolean isEmpty() {
+            return wrapped.isEmpty();
+        }
+        @Override
+        public boolean containsKey(Object key) {
+            return wrapped.containsKey(key);
+        }
+        @Override
+        public boolean containsValue(Object value) {
+            return wrapped.containsKey(value);
+        }
+        @Override
+        public Object get(Object key) {
+            return wrapped.get(key);
+        }
+        @Override
+        public Object put(String key, Object value) {
+            return wrapped.put(key, value);
+        }
+        @Override
+        public Object remove(Object key) {
+            return wrapped.remove(key);
+        }
+        @Override
+        public void putAll(Map<? extends String, ? extends Object> m) {
+            wrapped.putAll(m);
+        }
+        @Override
+        public Set<String> keySet() {
+            return wrapped.keySet();
+        }
+        @Override
+        public Collection<Object> values() {
+            return wrapped.values();
+        }
+        @Override
+        public Set<Entry<String, Object>> entrySet() {
+            return wrapped.entrySet();
+        }
+    }
+
+    public void setExecutor(Executor executor) {
+        if (!SynchronousExecutor.isA(executor)) {
+            this.executor = executor;
+        }
+    }
+
+    
+    public class IllegalEmptyResponseException extends IllegalStateException {
+        private static final long serialVersionUID = 1L;
+
+        public IllegalEmptyResponseException() {
+            super();
+        }
+
+        public IllegalEmptyResponseException(String message) {
+            super(message);
+        }
+
+        public IllegalEmptyResponseException(String message, Throwable cause) {
+            super(message, cause);
+        }
+
+        public IllegalEmptyResponseException(Throwable cause) {
+            super(cause);
+        }
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/endpoint/EndpointImpl.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/endpoint/EndpointImpl.java
new file mode 100644
index 0000000000..340211ba27
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/endpoint/EndpointImpl.java
@@ -0,0 +1,220 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.endpoint;
+
+import java.io.Closeable;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
+import java.util.logging.Logger;
+
+import javax.xml.namespace.QName;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusException;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.binding.Binding;
+import org.apache.cxf.binding.BindingFactory;
+import org.apache.cxf.binding.BindingFactoryManager;
+import org.apache.cxf.common.i18n.Message;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.configuration.Configurable;
+import org.apache.cxf.feature.Feature;
+import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.interceptor.AbstractAttributedInterceptorProvider;
+import org.apache.cxf.interceptor.ClientFaultConverter;
+import org.apache.cxf.interceptor.InFaultChainInitiatorObserver;
+import org.apache.cxf.interceptor.MessageSenderInterceptor;
+import org.apache.cxf.interceptor.OutFaultChainInitiatorObserver;
+import org.apache.cxf.service.Service;
+import org.apache.cxf.service.model.BindingInfo;
+import org.apache.cxf.service.model.EndpointInfo;
+import org.apache.cxf.transport.MessageObserver;
+
+public class EndpointImpl extends AbstractAttributedInterceptorProvider implements Endpoint, Configurable {
+
+    private static final long serialVersionUID = -7660560719050162091L;
+    private static final Logger LOG = LogUtils.getL7dLogger(EndpointImpl.class);
+    private static final ResourceBundle BUNDLE = LOG.getResourceBundle();
+
+    private Service service;
+    private Binding binding;
+    private EndpointInfo endpointInfo;
+    private Executor executor;
+    private Bus bus;
+    private MessageObserver inFaultObserver;
+    private MessageObserver outFaultObserver;
+    private List<Feature> activeFeatures;
+    private List<Closeable> cleanupHooks;
+
+    public EndpointImpl(Bus bus, Service s, QName endpointName) throws EndpointException {
+        this(bus, s, s.getEndpointInfo(endpointName));
+    }
+
+    public EndpointImpl(Bus bus, Service s, EndpointInfo ei) throws EndpointException {
+        if (ei == null) {
+            throw new NullPointerException("EndpointInfo can not be null!");
+        }
+
+        if (bus == null) {
+            this.bus = BusFactory.getThreadDefaultBus();
+        } else {
+            this.bus = bus;
+        }
+        service = s;
+        endpointInfo = ei;
+
+        createBinding(endpointInfo.getBinding());
+
+        inFaultObserver = new InFaultChainInitiatorObserver(bus);
+        outFaultObserver = new OutFaultChainInitiatorObserver(bus);
+
+        getInFaultInterceptors().add(new ClientFaultConverter());
+        getOutInterceptors().add(new MessageSenderInterceptor());
+        getOutFaultInterceptors().add(new MessageSenderInterceptor());
+    }
+
+    public String getBeanName() {
+        return endpointInfo.getName().toString() + ".endpoint";
+    }
+
+
+    public EndpointInfo getEndpointInfo() {
+        return endpointInfo;
+    }
+
+    public Service getService() {
+        return service;
+    }
+
+    public Binding getBinding() {
+        return binding;
+    }
+
+    public Executor getExecutor() {
+        return executor == null ? service.getExecutor() : executor;
+    }
+
+    public void setExecutor(Executor e) {
+        executor = e;
+    }
+
+    public Bus getBus() {
+        return bus;
+    }
+
+    public void setBus(Bus bus) {
+        this.bus = bus;
+    }
+
+    final void createBinding(BindingInfo bi) throws EndpointException {
+        if (null != bi) {
+            String namespace = bi.getBindingId();
+            try {
+                final BindingFactory bf = bus.getExtension(BindingFactoryManager.class).getBindingFactory(namespace);
+                if (null == bf) {
+                    Message msg = new Message("NO_BINDING_FACTORY", BUNDLE, namespace);
+                    throw new EndpointException(msg);
+                }
+                binding = bf.createBinding(bi);
+            } catch (BusException ex) {
+                throw new EndpointException(ex);
+            }
+        }
+    }
+
+
+    public MessageObserver getInFaultObserver() {
+        return inFaultObserver;
+    }
+
+    public MessageObserver getOutFaultObserver() {
+        return outFaultObserver;
+    }
+
+    public void setInFaultObserver(MessageObserver observer) {
+        inFaultObserver = observer;
+    }
+
+    public void setOutFaultObserver(MessageObserver observer) {
+        outFaultObserver = observer;
+
+    }
+
+    /**
+     * Utility method to make it easy to set properties from Spring.
+     *
+     * @param properties
+     */
+    public void setProperties(Map<String, Object> properties) {
+        this.putAll(properties);
+    }
+
+    /**
+     * @return the list of features <b>already</b> activated for this endpoint.
+     */
+    public List<Feature> getActiveFeatures() {
+        return activeFeatures;
+    }
+
+    /**
+     * @param features the list of features <b>already</b> activated for this endpoint.
+     */
+    public void initializeActiveFeatures(List<? extends Feature> features) {
+        activeFeatures = CastUtils.cast(features);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof EndpointImpl)) {
+            return false;
+        }
+
+        return super.equals(obj);
+    }
+
+    /**
+     * Returns the hashCode based on the EndpointInfo so that this object
+     * can be used as a map key.
+     */
+    @Override
+    public int hashCode() {
+        return endpointInfo.hashCode();
+    }
+
+    public synchronized void addCleanupHook(Closeable c) {
+        if (cleanupHooks == null) {
+            cleanupHooks = new CopyOnWriteArrayList<>();
+        }
+        cleanupHooks.add(c);
+    }
+    public List<Closeable> getCleanupHooks() {
+        if (cleanupHooks == null) {
+            return Collections.emptyList();
+        }
+        return cleanupHooks;
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/endpoint/ServerImpl.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/endpoint/ServerImpl.java
new file mode 100644
index 0000000000..c417cb6fe6
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/endpoint/ServerImpl.java
@@ -0,0 +1,221 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.endpoint;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.management.JMException;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusException;
+import org.apache.cxf.binding.BindingFactory;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.logging.RegexLoggingFilter;
+import org.apache.cxf.management.InstrumentationManager;
+import org.apache.cxf.service.model.EndpointInfo;
+import org.apache.cxf.transport.Destination;
+import org.apache.cxf.transport.DestinationFactory;
+import org.apache.cxf.transport.DestinationFactoryManager;
+import org.apache.cxf.transport.MessageObserver;
+import org.apache.cxf.transport.MultipleEndpointObserver;
+
+public class ServerImpl implements Server {
+    private static final Logger LOG = LogUtils.getL7dLogger(ServerImpl.class);
+
+    protected final Endpoint endpoint;
+    protected final Bus bus;
+    protected final BindingFactory bindingFactory;
+
+    private Destination destination;
+    private ServerRegistry serverRegistry;
+    private ServerLifeCycleManager slcMgr;
+    private InstrumentationManager iMgr;
+    private ManagedEndpoint mep;
+    private boolean stopped = true;
+    private boolean destroyDest = true;
+
+    public ServerImpl(Bus bus,
+                      Endpoint endpoint,
+                      DestinationFactory destinationFactory,
+                      BindingFactory bindingFactory) throws BusException, IOException {
+        this.endpoint = endpoint;
+        this.bus = bus;
+        this.bindingFactory = bindingFactory;
+
+        initDestination(destinationFactory);
+    }
+
+    private void initDestination(DestinationFactory destinationFactory) throws BusException, IOException {
+        EndpointInfo ei = endpoint.getEndpointInfo();
+
+        //Treat local transport as a special case, transports loaded by transportId can be replaced
+        //by local transport when the publishing address is a local transport protocol.
+        //Of course its not an ideal situation here to use a hard-coded prefix. To be refactored.
+        if (destinationFactory == null) {
+            if (ei.getAddress() != null && ei.getAddress().indexOf("local://") != -1) {
+                destinationFactory = bus.getExtension(DestinationFactoryManager.class)
+                    .getDestinationFactoryForUri(ei.getAddress());
+            }
+
+            if (destinationFactory == null) {
+                destinationFactory = bus.getExtension(DestinationFactoryManager.class)
+                    .getDestinationFactory(ei.getTransportId());
+            }
+        }
+
+        destination = destinationFactory.getDestination(ei, bus);
+        String wantFilter = ei.getAddress();
+        
+        if (wantFilter != null && wantFilter.startsWith("jms")) {
+            RegexLoggingFilter filter = new RegexLoggingFilter();
+            filter.setPattern("jms(.*?)password=+([^ ]+)");
+            filter.setGroup(2);
+            wantFilter = filter.filter(wantFilter).toString();
+        }
+        LOG.info("Setting the server's publish address to be " + wantFilter);
+        serverRegistry = bus.getExtension(ServerRegistry.class);
+
+        mep = new ManagedEndpoint(bus, endpoint, this);
+
+        slcMgr = bus.getExtension(ServerLifeCycleManager.class);
+        if (slcMgr != null) {
+            slcMgr.registerListener(mep);
+        }
+
+        iMgr = bus.getExtension(InstrumentationManager.class);
+        if (iMgr != null) {
+            try {
+                iMgr.register(mep);
+            } catch (JMException jmex) {
+                LOG.log(Level.WARNING, "Registering ManagedEndpoint failed.", jmex);
+            }
+        }
+    }
+
+    public Destination getDestination() {
+        return destination;
+    }
+
+    public void setDestination(Destination destination) {
+        this.destination = destination;
+    }
+
+    public void start() {
+        if (!stopped) {
+            return;
+        }
+        LOG.fine("Server is starting.");
+        
+        try {
+            bindingFactory.addListener(destination, endpoint);
+        } catch (RuntimeException e) {
+            if (e.getMessage().contains("endpoint already registered on address")) {
+                //this destination is used by another endpoint with same endpoint address
+                //so shouldn't be destroyed by this server
+                this.destroyDest = false;
+            }
+            throw e;
+        }
+
+        // register the active server to run
+        if (null != serverRegistry) {
+            LOG.fine("register the server to serverRegistry ");
+            serverRegistry.register(this);
+        }
+        if (slcMgr == null) {
+            slcMgr = bus.getExtension(ServerLifeCycleManager.class);
+            if (slcMgr != null && mep != null) {
+                slcMgr.registerListener(mep);
+            }
+        }
+        if (slcMgr != null) {
+            slcMgr.startServer(this);
+        }
+        stopped = false;
+    }
+
+    public boolean isStopped() {
+        return stopped;
+    }
+    public boolean isStarted() {
+        return !stopped;
+    }
+
+    public void stop() {
+        if (stopped) {
+            return;
+        }
+
+        LOG.fine("Server is stopping.");
+
+        for (Closeable c : endpoint.getCleanupHooks()) {
+            try {
+                c.close();
+            } catch (IOException e) {
+                //ignore
+            }
+        }
+        if (slcMgr != null) {
+            slcMgr.stopServer(this);
+        }
+
+        MessageObserver mo = getDestination().getMessageObserver();
+        if (mo instanceof MultipleEndpointObserver) {
+            ((MultipleEndpointObserver)mo).getEndpoints().remove(endpoint);
+            if (((MultipleEndpointObserver)mo).getEndpoints().isEmpty()) {
+                getDestination().setMessageObserver(null);
+            }
+        } else {
+            getDestination().setMessageObserver(null);
+        }
+        stopped = true;
+    }
+
+    public void destroy() {
+        stop();
+        if (this.destroyDest) {
+            //we should shutdown the destination here
+            getDestination().shutdown();
+        }
+
+        if (null != serverRegistry) {
+            LOG.fine("unregister the server to serverRegistry ");
+            serverRegistry.unregister(this);
+        }
+
+        if (iMgr != null) {
+            try {
+                iMgr.unregister(mep);
+            } catch (JMException jmex) {
+                LOG.log(Level.WARNING, "Unregistering ManagedEndpoint failed.", jmex);
+            }
+            iMgr = null;
+        }
+
+    }
+
+    public Endpoint getEndpoint() {
+        return endpoint;
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/feature/FastInfosetFeature.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/feature/FastInfosetFeature.java
new file mode 100644
index 0000000000..daa4bd38ca
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/feature/FastInfosetFeature.java
@@ -0,0 +1,110 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.feature;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.injection.NoJSR250Annotations;
+import org.apache.cxf.interceptor.FIStaxInInterceptor;
+import org.apache.cxf.interceptor.FIStaxOutInterceptor;
+import org.apache.cxf.interceptor.InterceptorProvider;
+
+
+/**
+ * <pre>
+ * <![CDATA[
+    <jaxws:endpoint ...>
+      <jaxws:features>
+       <bean class="org.apache.cxf.feature.FastInfosetFeature"/>
+      </jaxws:features>
+    </jaxws:endpoint>
+  ]]>
+  </pre>
+ */
+@NoJSR250Annotations
+public class FastInfosetFeature extends DelegatingFeature<FastInfosetFeature.Portable> {
+    public FastInfosetFeature() {
+        super(new Portable());
+    }
+
+    public void setForce(boolean b) {
+        delegate.setForce(b);
+    }
+
+    public boolean getForce() {
+        return delegate.getForce();
+    }
+
+    public static class Portable implements AbstractPortableFeature {
+        boolean force;
+        private Integer serializerAttributeValueMapMemoryLimit;
+        private Integer serializerMinAttributeValueSize;
+        private Integer serializerMaxAttributeValueSize;
+        private Integer serializerCharacterContentChunkMapMemoryLimit;
+        private Integer serializerMinCharacterContentChunkSize;
+        private Integer serializerMaxCharacterContentChunkSize;
+
+        @Override
+        public void doInitializeProvider(InterceptorProvider provider, Bus bus) {
+
+            FIStaxInInterceptor in = new FIStaxInInterceptor();
+
+            FIStaxOutInterceptor out = new FIStaxOutInterceptor(force);
+            if (serializerAttributeValueMapMemoryLimit != null && serializerAttributeValueMapMemoryLimit > 0) {
+                out.setSerializerAttributeValueMapMemoryLimit(serializerAttributeValueMapMemoryLimit);
+            }
+            if (serializerMinAttributeValueSize != null && serializerMinAttributeValueSize > 0) {
+                out.setSerializerMinAttributeValueSize(serializerMinAttributeValueSize);
+            }
+            if (serializerMaxAttributeValueSize != null && serializerMaxAttributeValueSize > 0) {
+                out.setSerializerMaxAttributeValueSize(serializerMaxAttributeValueSize);
+            }
+            if (serializerCharacterContentChunkMapMemoryLimit != null
+                    && serializerCharacterContentChunkMapMemoryLimit > 0) {
+                out.setSerializerCharacterContentChunkMapMemoryLimit(
+                        serializerCharacterContentChunkMapMemoryLimit);
+            }
+            if (serializerMinCharacterContentChunkSize != null && serializerMinCharacterContentChunkSize > 0) {
+                out.setSerializerMinCharacterContentChunkSize(serializerMinCharacterContentChunkSize);
+            }
+            if (serializerMaxCharacterContentChunkSize != null && serializerMaxCharacterContentChunkSize > 0) {
+                out.setSerializerMaxCharacterContentChunkSize(serializerMaxCharacterContentChunkSize);
+            }
+
+            provider.getInInterceptors().add(in);
+            provider.getInFaultInterceptors().add(in);
+            provider.getOutInterceptors().add(out);
+            provider.getOutFaultInterceptors().add(out);
+        }
+
+        /**
+         * Set if FastInfoset is always used without negotiation
+         * @param b
+         */
+        public void setForce(boolean b) {
+            force = b;
+        }
+
+        /**
+         * Retrieve the value set with {@link #setForce(boolean)}.
+         */
+        public boolean getForce() {
+            return force;
+        }
+    }
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/feature/WrappedFeature.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/feature/WrappedFeature.java
new file mode 100644
index 0000000000..2236a38e4d
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/feature/WrappedFeature.java
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.feature;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.endpoint.Client;
+import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.interceptor.InterceptorProvider;
+
+/**
+ * A Feature is something that is able to customize a Server, Client, or Bus, typically
+ * adding capabilities. For instance, there may be a LoggingFeature which configures
+ * one of the above to log each of their messages.
+ * <p>
+ * By default the initialize methods all delegate to initializeProvider(InterceptorProvider).
+ * If you're simply adding interceptors to a Server, Client, or Bus, this allows you to add
+ * them easily.
+ */
+public class WrappedFeature extends AbstractFeature {
+    final Feature wrapped;
+    public WrappedFeature(Feature f) {
+        wrapped = f;
+    }
+
+    @Override
+    public void initialize(Server server, Bus bus) {
+        wrapped.initialize(server, bus);
+    }
+
+    @Override
+    public void initialize(Client client, Bus bus) {
+        wrapped.initialize(client, bus);
+    }
+
+    @Override
+    public void initialize(InterceptorProvider interceptorProvider, Bus bus) {
+        wrapped.initialize(interceptorProvider, bus);
+    }
+
+    @Override
+    public void initialize(Bus bus) {
+        wrapped.initialize(bus);
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/feature/transform/XSLTOutInterceptor.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/feature/transform/XSLTOutInterceptor.java
new file mode 100644
index 0000000000..53605ccace
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/feature/transform/XSLTOutInterceptor.java
@@ -0,0 +1,210 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.feature.transform;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.logging.Logger;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.transform.Templates;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.interceptor.StaxOutInterceptor;
+import org.apache.cxf.io.CachedOutputStream;
+import org.apache.cxf.io.CachedOutputStreamCallback;
+import org.apache.cxf.io.CachedWriter;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.Phase;
+import org.apache.cxf.staxutils.DelegatingXMLStreamWriter;
+import org.apache.cxf.staxutils.StaxUtils;
+
+/** Class provides XSLT transformation of outgoing message.
+ * Actually it breaks streaming (can be fixed in further versions when XSLT engine supports XML stream)
+ */
+public class XSLTOutInterceptor extends AbstractXSLTInterceptor {
+    private static final Logger LOG = LogUtils.getL7dLogger(XSLTOutInterceptor.class);
+
+    public XSLTOutInterceptor(String xsltPath) {
+        super(Phase.PRE_STREAM, StaxOutInterceptor.class, null, xsltPath);
+    }
+
+    public XSLTOutInterceptor(String phase, Class<?> before, Class<?> after, String xsltPath) {
+        super(phase, before, after, xsltPath);
+    }
+
+    @Override
+    public void handleMessage(Message message) {
+        if (checkContextProperty(message)) {
+            return;
+        }
+
+        // 1. Try to get and transform XMLStreamWriter message content
+        XMLStreamWriter xWriter = message.getContent(XMLStreamWriter.class);
+        if (xWriter != null) {
+            transformXWriter(message, xWriter);
+        } else {
+            // 2. Try to get and transform OutputStream message content
+            OutputStream out = message.getContent(OutputStream.class);
+            if (out != null) {
+                transformOS(message, out);
+            } else {
+                // 3. Try to get and transform Writer message content (actually used for JMS TextMessage)
+                Writer writer = message.getContent(Writer.class);
+                if (writer != null) {
+                    transformWriter(message, writer);
+                }
+            }
+        }
+    }
+
+    protected void transformXWriter(Message message, XMLStreamWriter xWriter) {
+        CachedWriter writer = new CachedWriter();
+        XMLStreamWriter delegate = StaxUtils.createXMLStreamWriter(writer);
+        XSLTStreamWriter wrapper = new XSLTStreamWriter(getXSLTTemplate(), writer, delegate, xWriter);
+        message.setContent(XMLStreamWriter.class, wrapper);
+        message.put(AbstractOutDatabindingInterceptor.DISABLE_OUTPUTSTREAM_OPTIMIZATION,
+                    Boolean.TRUE);
+    }
+
+    protected void transformOS(Message message, OutputStream out) {
+        CachedOutputStream wrapper = new CachedOutputStream();
+        CachedOutputStreamCallback callback = new XSLTCachedOutputStreamCallback(getXSLTTemplate(), out);
+        wrapper.registerCallback(callback);
+        message.setContent(OutputStream.class, wrapper);
+    }
+
+    protected void transformWriter(Message message, Writer writer) {
+        XSLTCachedWriter wrapper = new XSLTCachedWriter(getXSLTTemplate(), writer);
+        message.setContent(Writer.class, wrapper);
+    }
+
+
+    public static class XSLTStreamWriter extends DelegatingXMLStreamWriter {
+        private final Templates xsltTemplate;
+        private final CachedWriter cachedWriter;
+        private final XMLStreamWriter origXWriter;
+
+        public XSLTStreamWriter(Templates xsltTemplate, CachedWriter cachedWriter,
+                                XMLStreamWriter delegateXWriter, XMLStreamWriter origXWriter) {
+            super(delegateXWriter);
+            this.xsltTemplate = xsltTemplate;
+            this.cachedWriter = cachedWriter;
+            this.origXWriter = origXWriter;
+        }
+
+        @Override
+        public void close() {
+            Reader transformedReader = null;
+            try {
+                super.flush();
+                transformedReader = XSLTUtils.transform(xsltTemplate, cachedWriter.getReader());
+                StaxUtils.copy(new StreamSource(transformedReader), origXWriter);
+            } catch (XMLStreamException e) {
+                throw new Fault("STAX_COPY", LOG, e, e.getMessage());
+            } catch (IOException e) {
+                throw new Fault("GET_CACHED_INPUT_STREAM", LOG, e, e.getMessage());
+            } finally {
+                try {
+                    if (transformedReader != null) {
+                        transformedReader.close();
+                    }
+                    cachedWriter.close();
+                    StaxUtils.close(origXWriter);
+                    super.close();
+                } catch (Exception e) {
+                    LOG.warning("Cannot close stream after transformation: " + e.getMessage());
+                }
+            }
+        }
+    }
+
+    public static class XSLTCachedOutputStreamCallback implements CachedOutputStreamCallback {
+        private final Templates xsltTemplate;
+        private final OutputStream origStream;
+
+        public XSLTCachedOutputStreamCallback(Templates xsltTemplate, OutputStream origStream) {
+            this.xsltTemplate = xsltTemplate;
+            this.origStream = origStream;
+        }
+
+        @Override
+        public void onFlush(CachedOutputStream wrapper) {
+        }
+
+        @Override
+        public void onClose(CachedOutputStream wrapper) {
+            InputStream transformedStream;
+            Exception exceptionOnClose = null;
+            try {
+                transformedStream = XSLTUtils.transform(xsltTemplate, wrapper.getInputStream());
+                IOUtils.copyAndCloseInput(transformedStream, origStream);
+            } catch (IOException e) {
+                throw new Fault("STREAM_COPY", LOG, e, e.getMessage());
+            } finally {
+                try {
+                    origStream.close();
+                } catch (Exception e) {
+                    exceptionOnClose = e;
+                }
+            }
+            
+            if (exceptionOnClose == null) {
+                return;
+            }
+            throw new Fault(exceptionOnClose);
+        }
+    }
+
+    public static class XSLTCachedWriter extends CachedWriter {
+        private final Templates xsltTemplate;
+        private final Writer origWriter;
+
+        public XSLTCachedWriter(Templates xsltTemplate, Writer origWriter) {
+            this.xsltTemplate = xsltTemplate;
+            this.origWriter = origWriter;
+        }
+
+        @Override
+        protected void doClose() {
+            try {
+                final Reader transformedReader = XSLTUtils.transform(xsltTemplate, getReader());
+                IOUtils.copyAndCloseInput(transformedReader, origWriter, IOUtils.DEFAULT_BUFFER_SIZE);
+            } catch (IOException e) {
+                throw new Fault("READER_COPY", LOG, e, e.getMessage());
+            } finally {
+                try {
+                    origWriter.close();
+                } catch (IOException e) {
+                    LOG.warning("Cannot close stream after transformation: " + e.getMessage());
+                }
+            }
+        }
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/headers/Header.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/headers/Header.java
new file mode 100644
index 0000000000..f933c14dba
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/headers/Header.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.headers;
+
+import javax.xml.namespace.QName;
+
+import org.apache.cxf.databinding.DataBinding;
+
+public class Header {
+    public enum Direction  {
+        DIRECTION_IN,
+        DIRECTION_OUT,
+        DIRECTION_INOUT
+    }
+
+    public static final String HEADER_LIST = Header.class.getName() + ".list";
+
+
+    private DataBinding dataBinding;
+    private QName name;
+    private Object object;
+
+    private Direction direction = Header.Direction.DIRECTION_OUT;
+
+    public Header(QName q, Object o) {
+        this(q, o, null);
+    }
+
+    public Header(QName q, Object o, DataBinding b) {
+        object = o;
+        name = q;
+        dataBinding = b;
+    }
+
+    public DataBinding getDataBinding() {
+        return dataBinding;
+    }
+    public void setDataBinding(DataBinding dataBinding) {
+        this.dataBinding = dataBinding;
+    }
+    public QName getName() {
+        return name;
+    }
+    public void setName(QName name) {
+        this.name = name;
+    }
+    public Object getObject() {
+        return object;
+    }
+    public void setObject(Object object) {
+        this.object = object;
+    }
+
+    public void setDirection(Direction hdrDirection) {
+        this.direction = hdrDirection;
+    }
+
+    public Direction getDirection() {
+        return direction;
+    }
+
+}
diff --git a/deps/cxf-shade/src/patch/java/org/apache/cxf/helpers/DOMUtils.java b/deps/cxf-shade/src/patch/java/org/apache/cxf/helpers/DOMUtils.java
new file mode 100644
index 0000000000..37bde6779d
--- /dev/null
+++ b/deps/cxf-shade/src/patch/java/org/apache/cxf/helpers/DOMUtils.java
@@ -0,0 +1,895 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.cxf.helpers;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.ReflectionUtil;
+import org.apache.cxf.common.util.StringUtils;
+
+/**
+ * Few simple utils to read DOM. This is originally from the Jakarta Commons Modeler.
+ */
+public final class DOMUtils {
+    private static boolean isJre9SAAJ;
+    private static final Map<ClassLoader, DocumentBuilder> DOCUMENT_BUILDERS
+        = Collections.synchronizedMap(new WeakHashMap<ClassLoader, DocumentBuilder>());
+    private static final String XMLNAMESPACE = "xmlns";
+    private static volatile Document emptyDocument;
+
+    private static final ClassValue<Method> GET_DOM_ELEMENTS_METHODS = new ClassValue<Method>() {
+        @Override
+        protected Method computeValue(Class<?> type) {
+            try {
+                return ReflectionUtil.getMethod(type, "getDomElement");
+            } catch (NoSuchMethodException e) {
+                //best effort to try, do nothing if NoSuchMethodException
+                return null;
+            }
+        }
+    };
+    private static final ClassValue<Field> GET_DOCUMENT_FRAGMENT_FIELDS = new ClassValue<Field>() {
+        @Override
+        protected Field computeValue(Class<?> type) {
+            return ReflectionUtil.getDeclaredField(type, "documentFragment");
+        }
+
+    };
+
+    static {
+        try {
+            Method[] methods = DOMUtils.class.getClassLoader().
+                loadClass("com.sun.xml.messaging.saaj.soap.SOAPDocumentImpl").getMethods();
+            for (Method method : methods) {
+                if ("register".equals(method.getName())) {
+                    //this is the 1.4+ SAAJ impl
+                    setJava9SAAJ(true);
+                    break;
+                }
+            }
+        } catch (ClassNotFoundException cnfe) {
+            LogUtils.getL7dLogger(DOMUtils.class).finest(
+                "can't load class com.sun.xml.messaging.saaj.soap.SOAPDocumentImpl");
+
+            try {
+                Method[] methods = DOMUtils.class.getClassLoader().
+                    loadClass("com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl").getMethods();
+                for (Method method : methods) {
+                    if ("register".equals(method.getName())) {
+                        //this is the SAAJ impl in JDK9
+                        setJava9SAAJ(true);
+                        break;
+                    }
+                }
+            } catch (ClassNotFoundException cnfe1) {
+                LogUtils.getL7dLogger(DOMUtils.class).finest(
+                    "can't load class com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl");
+            }
+        } catch (Throwable throwable) {
+            LogUtils.getL7dLogger(DOMUtils.class).finest(
+                "Other JDK vendor");
+        }
+    }
+
+    private DOMUtils() {
+    }
+
+    private static DocumentBuilder getDocumentBuilder() throws ParserConfigurationException {
+        ClassLoader loader = getContextClassLoader();
+        if (loader == null) {
+            loader = getClassLoader(DOMUtils.class);
+        }
+        if (loader == null) {
+            return createDocumentBuilder();
+        }
+        DocumentBuilder factory = DOCUMENT_BUILDERS.get(loader);
+        if (factory == null) {
+            factory = createDocumentBuilder();
+            DOCUMENT_BUILDERS.put(loader, factory);
+        }
+        return factory;
+    }
+
+    private static DocumentBuilder createDocumentBuilder() throws ParserConfigurationException {
+        DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
+        f.setNamespaceAware(true);
+        f.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true);
+        f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+        return f.newDocumentBuilder();
+    }
+
+    private static ClassLoader getContextClassLoader() {
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+                public ClassLoader run() {
+                    return Thread.currentThread().getContextClassLoader();
+                }
+            });
+        }
+        return Thread.currentThread().getContextClassLoader();
+    }
+
+    private static ClassLoader getClassLoader(final Class<?> clazz) {
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+                public ClassLoader run() {
+                    return clazz.getClassLoader();
+                }
+            });
+        }
+        return clazz.getClassLoader();
+    }
+
+    /**
+     * Creates a new Document object
+     * @throws ParserConfigurationException
+     */
+    public static Document newDocument() {
+        return createDocument();
+    }
+    public static Document createDocument() {
+        try {
+            return getDocumentBuilder().newDocument();
+        } catch (ParserConfigurationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static synchronized Document createEmptyDocument() {
+        if (emptyDocument == null) {
+            emptyDocument = createDocument();
+
+            // uncomment this to see if anything is actually setting anything into the empty doc
+            /*
+            final Document doc  = createDocument();
+            emptyDocument = (Document)org.apache.cxf.common.util.ProxyHelper.getProxy(
+                DOMUtils.class.getClassLoader(),
+                new Class<?>[] {Document.class},
+                new java.lang.reflect.InvocationHandler() {
+                    @Override
+                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+                        if (method.getName().contains("create")) {
+                            return method.invoke(doc, args);
+                        }
+                        throw new IllegalStateException("Cannot modify factory document");
+                    }
+                });
+            */
+        }
+        return emptyDocument;
+    }
+    /**
+     * Returns a static Document that should always be "empty".  It's useful as a factory for
+     * for creating Elements and other nodes that will be traversed later and don't need to
+     * be attached into a document
+     * @return an empty document
+     */
+    public static Document getEmptyDocument() {
+        Document doc = emptyDocument;
+        if (doc == null) {
+            doc = createEmptyDocument();
+        }
+        return doc;
+    }
+
+
+    /**
+     * This function is much like getAttribute, but returns null, not "", for a nonexistent attribute.
+     *
+     * @param e
+     * @param attributeName
+     */
+    public static String getAttributeValueEmptyNull(Element e, String attributeName) {
+        Attr node = e.getAttributeNode(attributeName);
+        if (node == null) {
+            return null;
+        }
+        return node.getValue();
+    }
+
+    /**
+     * Get the text content of a node and all it's children or null if there is no text
+     */
+    public static String getAllContent(Node n) {
+        StringBuilder b = new StringBuilder();
+        getAllContent(n, b);
+        return b.toString();
+    }
+    private static void getAllContent(Node n, StringBuilder b) {
+        Node nd = n.getFirstChild();
+        while (nd != null) {
+            if (nd instanceof Text && !(nd instanceof Comment)) {
+                b.append(((Text)nd).getData());
+            } else {
+                getAllContent(nd, b);
+            }
+            nd = nd.getNextSibling();
+        }
+    }
+    /**
+     * Get the trimmed text content of a node or null if there is no text
+     */
+    public static String getContent(Node n) {
+        String s = getRawContent(n);
+        if (s != null) {
+            s = s.trim();
+        }
+        return s;
+    }
+
+    /**
+     * Get the raw text content of a node or null if there is no text
+     */
+    public static String getRawContent(Node n) {
+        if (n == null) {
+            return null;
+        }
+        StringBuilder b = null;
+        String s = null;
+        Node n1 = n.getFirstChild();
+        while (n1 != null) {
+            if (n1.getNodeType() == Node.TEXT_NODE || n1.getNodeType() == Node.CDATA_SECTION_NODE) {
+                if (b != null) {
+                    b.append(((Text)n1).getNodeValue());
+                } else if (s == null) {
+                    s = ((Text)n1).getNodeValue();
+                } else {
+                    b = new StringBuilder(s).append(((Text)n1).getNodeValue());
+                    s = null;
+                }
+            }
+            n1 = n1.getNextSibling();
+        }
+        if (b != null) {
+            return b.toString();
+        }
+        return s;
+    }
+
+    /**
+     * Get the first element child.
+     *
+     * @param parent lookup direct childs
+     * @param name name of the element. If null return the first element.
+     */
+    public static Node getChild(Node parent, String name) {
+        if (parent == null) {
+            return null;
+        }
+
+        Node first = parent.getFirstChild();
+        if (first == null) {
+            return null;
+        }
+
+        for (Node node = first; node != null; node = node.getNextSibling()) {
+            
+            if (node.getNodeType() != Node.ELEMENT_NODE) {
+                continue;
+            }
+            if (name != null && name.equals(node.getNodeName())) {
+                return node;
+            }
+            if (name == null) {
... 9547 lines suppressed ...