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

reta pushed a commit to branch 3.6.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git


The following commit(s) were added to refs/heads/3.6.x-fixes by this push:
     new 0ce3df36ab CXF-9007: NullPointerException in 
XMLStreamDataWriter.writeNode (#1861)
0ce3df36ab is described below

commit 0ce3df36abc2a53f4e30ea8b958b825ac8f6a6a7
Author: Andriy Redko <[email protected]>
AuthorDate: Tue Jun 18 17:21:25 2024 -0400

    CXF-9007: NullPointerException in XMLStreamDataWriter.writeNode (#1861)
---
 .../main/java/org/apache/cxf/helpers/DOMUtils.java |   5 +-
 systests/transport-hc5/pom.xml                     |  10 ++
 .../systest/hc5/jaxws/JAXWSAsyncClientTest.java    | 105 ++++++++++++-
 .../org/apache/cxf/systest/hc5/jaxws/greeting.wsdl | 166 +++++++++++++++++++++
 4 files changed, 284 insertions(+), 2 deletions(-)

diff --git a/core/src/main/java/org/apache/cxf/helpers/DOMUtils.java 
b/core/src/main/java/org/apache/cxf/helpers/DOMUtils.java
index 37bde6779d..c781719f01 100644
--- a/core/src/main/java/org/apache/cxf/helpers/DOMUtils.java
+++ b/core/src/main/java/org/apache/cxf/helpers/DOMUtils.java
@@ -790,7 +790,10 @@ public final class DOMUtils {
             //java9 plus hack
             Field f = GET_DOCUMENT_FRAGMENT_FIELDS.get(fragment.getClass());
             if (f != null) {
-                return ReflectionUtil.accessDeclaredField(f, fragment, 
DocumentFragment.class);
+                final DocumentFragment inner = 
ReflectionUtil.accessDeclaredField(f, fragment, DocumentFragment.class);
+                if (inner != null) {
+                    return inner;
+                }
             }
         }
         return fragment;
diff --git a/systests/transport-hc5/pom.xml b/systests/transport-hc5/pom.xml
index 91471c40d4..540c568afb 100644
--- a/systests/transport-hc5/pom.xml
+++ b/systests/transport-hc5/pom.xml
@@ -249,5 +249,15 @@
             <artifactId>spring-boot-starter-web</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>jakarta.xml.soap</groupId>
+            <artifactId>jakarta.xml.soap-api</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.xml.messaging.saaj</groupId>
+            <artifactId>saaj-impl</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git 
a/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/jaxws/JAXWSAsyncClientTest.java
 
b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/jaxws/JAXWSAsyncClientTest.java
index 31d2579263..20133d67ae 100644
--- 
a/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/jaxws/JAXWSAsyncClientTest.java
+++ 
b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/jaxws/JAXWSAsyncClientTest.java
@@ -20,10 +20,31 @@
 package org.apache.cxf.systest.hc5.jaxws;
 
 import java.util.Random;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
+import javax.xml.namespace.QName;
+import javax.xml.soap.MessageFactory;
+import javax.xml.soap.SOAPException;
+import javax.xml.soap.SOAPMessage;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
 import javax.jws.WebService;
+import javax.xml.ws.Dispatch;
 import javax.xml.ws.Response;
+import javax.xml.ws.Service;
+import javax.xml.ws.soap.SOAPBinding;
 import javax.xml.ws.soap.SOAPFaultException;
 
 import org.apache.cxf.endpoint.Client;
@@ -43,13 +64,15 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 
 import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 public class JAXWSAsyncClientTest  extends AbstractBusClientServerTestBase {
     static final String PORT = allocatePort(Server.class);
-
+    static ScheduledExecutorService executor;
+    
     public static class Server extends AbstractBusTestServerBase {
 
         protected void run()  {
@@ -95,11 +118,18 @@ public class JAXWSAsyncClientTest  extends 
AbstractBusClientServerTestBase {
     @BeforeClass
     public static void startServers() throws Exception {
         assertTrue("server did not launch correctly", 
launchServer(Server.class, true));
+        executor = Executors.newScheduledThreadPool(5);
     }
 
     @AfterClass
     public static void stopServers() throws Exception {
         stopAllServers();
+        if (executor != null) {
+            executor.shutdown();
+            if (!executor.awaitTermination(1, TimeUnit.MINUTES)) {
+                executor.shutdownNow();
+            }
+        }
     }
 
     @Test
@@ -176,4 +206,77 @@ public class JAXWSAsyncClientTest  extends 
AbstractBusClientServerTestBase {
                        || ex.getCause() instanceof 
java.net.SocketTimeoutException);
         }
     }
+    
+    /**
+     * Not 100% reproducible but used to sporadically fail with:
+     * 
+     * java.util.concurrent.ExecutionException: 
jakarta.xml.ws.soap.SOAPFaultException: 
+     *   Cannot invoke "org.w3c.dom.Node.getOwnerDocument()" because "nd" is 
null
+     *   at 
java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:396)
+     *   at 
java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2073)
+     *   at org.apache.cxf.endpoint.ClientCallback.get(ClientCallback.java:139)
+     *   at 
org.apache.cxf.jaxws.JaxwsResponseCallback.get(JaxwsResponseCallback.java:48)
+     *   at 
org.apache.cxf.systest.hc5.jaxws.JAXWSAsyncClientTest.testAsyncWsdl(JAXWSAsyncClientTest.java:193)
+     *
+     * @see https://issues.apache.org/jira/browse/CXF-9007
+     */
+    @Test
+    public void testAsyncWsdl() throws Exception {
+        final URL wsdlUrl = 
getClass().getClassLoader().getResource("greeting.wsdl");
+
+        final Service service = Service.create(wsdlUrl, new 
QName("http://apache.org/hello_world";, "SOAPService"));
+
+        service.addPort(new QName("http://apache.org/hello_world";, "Greeter"), 
SOAPBinding.SOAP11HTTP_BINDING,
+                "http://localhost:"; + PORT + "/SoapContext/GreeterPort");
+
+        final Dispatch<SOAPMessage> client = service.createDispatch(
+                new QName("http://apache.org/hello_world";, "Greeter"),
+                SOAPMessage.class,
+                Service.Mode.MESSAGE
+        );
+
+        final List<Future<Response<SOAPMessage>>> tasks = new ArrayList<>();
+        for (int i = 0; i < 50; i++) {
+            tasks.add(executor.submit(() -> 
client.invokeAsync(buildMessage())));
+        }
+
+        for (Future<Response<SOAPMessage>> task : tasks) {
+            final SOAPMessage result = task.get(5, TimeUnit.SECONDS).get();
+            verifyResult(result);
+        }
+    }
+
+    private static void verifyResult(SOAPMessage message) throws Exception {
+        TransformerFactory tf = TransformerFactory.newInstance();
+        Transformer transformer = tf.newTransformer();
+        
+        String output =  null;
+        try (StringWriter writer = new StringWriter()) {
+            final DOMSource source = new 
DOMSource(message.getSOAPBody().extractContentAsDocument());
+            transformer.transform(source, new StreamResult(writer));
+            output = writer.getBuffer().toString().replaceAll("\n|\r", "");
+        }
+
+        assertThat(output, containsString("HELLO"));
+    }
+
+    private static SOAPMessage buildMessage() throws SOAPException, 
IOException {
+        String soapMessage = 
+            "<soapenv:Envelope 
xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\";>"
+            + "<soapenv:Header/>"
+            + "  <soapenv:Body>"
+            + "    <ns2:greetMe 
xmlns:ns2=\"http://cxf.apache.org/greeter_control/types\";>"
+            + "        <ns2:requestType>Hello</ns2:requestType>"
+            + "    </ns2:greetMe>"
+            + "  </soapenv:Body>"
+            + "</soapenv:Envelope>";
+
+        SOAPMessage message = null;
+        try (ByteArrayInputStream bis = new 
ByteArrayInputStream(soapMessage.getBytes())) {
+            message = MessageFactory.newInstance().createMessage(null, bis);
+            message.saveChanges();
+        }
+
+        return message;
+    }
 }
diff --git 
a/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/jaxws/greeting.wsdl
 
b/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/jaxws/greeting.wsdl
new file mode 100644
index 0000000000..c12bdfe88a
--- /dev/null
+++ 
b/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/jaxws/greeting.wsdl
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<wsdl:definitions xmlns="http://schemas.xmlsoap.org/wsdl/"; 
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"; 
xmlns:tns="http://apache.org/hello_world"; 
xmlns:x1="http://apache.org/hello_world/types"; 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"; 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"; name="HelloWorld" 
targetNamespace="http://apache.org/hello_world";>
+    <wsdl:types>
+        <schema xmlns="http://www.w3.org/2001/XMLSchema"; 
xmlns:tns="http://apache.org/hello_world/types"; 
targetNamespace="http://apache.org/hello_world/types"; 
elementFormDefault="qualified">
+            <simpleType name="MyStringType">
+                <restriction base="string">
+                    <maxLength value="30"/>
+                </restriction>
+            </simpleType>
+            <element name="sayHi">
+                <complexType/>
+            </element>
+            <element name="sayHiResponse">
+                <complexType>
+                    <sequence>
+                        <element name="responseType" type="string"/>
+                    </sequence>
+                </complexType>
+            </element>
+            <element name="greetMe">
+                <complexType>
+                    <sequence>
+                        <element name="requestType" type="tns:MyStringType"/>
+                    </sequence>
+                </complexType>
+            </element>
+            <element name="greetMeResponse">
+                <complexType>
+                    <sequence>
+                        <element name="responseType" type="string"/>
+                    </sequence>
+                </complexType>
+            </element>
+            <element name="pingMe">
+                <complexType/>
+            </element>
+            <element name="pingMeResponse">
+                <complexType/>
+            </element>
+            <element name="faultDetail">
+                <complexType>
+                    <sequence>
+                        <element name="minor" type="short"/>
+                        <element name="major" type="short"/>
+                    </sequence>
+                </complexType>
+            </element>
+        </schema>
+    </wsdl:types>
+    <wsdl:message name="sayHiRequest">
+        <wsdl:part element="x1:sayHi" name="in"/>
+    </wsdl:message>
+    <wsdl:message name="sayHiResponse">
+        <wsdl:part element="x1:sayHiResponse" name="out"/>
+    </wsdl:message>
+    <wsdl:message name="greetMeRequest">
+        <wsdl:part element="x1:greetMe" name="in"/>
+    </wsdl:message>
+    <wsdl:message name="greetMeResponse">
+        <wsdl:part element="x1:greetMeResponse" name="out"/>
+    </wsdl:message>
+    <wsdl:message name="pingMeRequest">
+        <wsdl:part name="in" element="x1:pingMe"/>
+    </wsdl:message>
+    <wsdl:message name="pingMeResponse">
+        <wsdl:part name="out" element="x1:pingMeResponse"/>
+    </wsdl:message>
+    <wsdl:message name="pingMeFault">
+        <wsdl:part name="faultDetail" element="x1:faultDetail"/>
+    </wsdl:message>
+    <wsdl:portType name="Greeter">
+        <wsdl:operation name="sayHi">
+            <wsdl:input message="tns:sayHiRequest" name="sayHiRequest"/>
+            <wsdl:output message="tns:sayHiResponse" name="sayHiResponse"/>
+        </wsdl:operation>
+        <wsdl:operation name="greetMe">
+            <wsdl:input message="tns:greetMeRequest" name="greetMeRequest"/>
+            <wsdl:output message="tns:greetMeResponse" name="greetMeResponse"/>
+        </wsdl:operation>
+        <wsdl:operation name="pingMe">
+            <wsdl:input name="pingMeRequest" message="tns:pingMeRequest"/>
+            <wsdl:output name="pingMeResponse" message="tns:pingMeResponse"/>
+            <wsdl:fault name="pingMeFault" message="tns:pingMeFault"/>
+        </wsdl:operation>
+    </wsdl:portType>
+    <wsdl:binding name="Greeter_SOAPBinding" type="tns:Greeter">
+        <soap:binding style="document" 
transport="http://schemas.xmlsoap.org/soap/http"/>
+        <wsdl:operation name="sayHi">
+            <soap:operation soapAction="" style="document"/>
+            <wsdl:input name="sayHiRequest">
+                <soap:body use="literal"/>
+            </wsdl:input>
+            <wsdl:output name="sayHiResponse">
+                <soap:body use="literal"/>
+            </wsdl:output>
+        </wsdl:operation>
+        <wsdl:operation name="greetMe">
+            <soap:operation soapAction="" style="document"/>
+            <wsdl:input name="greetMeRequest">
+                <soap:body use="literal"/>
+            </wsdl:input>
+            <wsdl:output name="greetMeResponse">
+                <soap:body use="literal"/>
+            </wsdl:output>
+        </wsdl:operation>
+        <wsdl:operation name="pingMe">
+            <soap:operation style="document"/>
+            <wsdl:input>
+                <soap:body use="literal"/>
+            </wsdl:input>
+            <wsdl:output>
+                <soap:body use="literal"/>
+            </wsdl:output>
+            <wsdl:fault name="pingMeFault">
+                <soap:fault name="pingMeFault" use="literal"/>
+            </wsdl:fault>
+        </wsdl:operation>
+    </wsdl:binding>
+    <wsdl:service name="SOAPService">
+        <wsdl:port binding="tns:Greeter_SOAPBinding" name="Mortimer">
+            <soap:address location="http://localhost:9000/Mortimer"/>
+        </wsdl:port>
+        <wsdl:port binding="tns:Greeter_SOAPBinding" name="Tarpin">
+            <soap:address location="https://localhost:9003/Tarpin"/>
+        </wsdl:port>
+        <wsdl:port binding="tns:Greeter_SOAPBinding" name="Rethwel">
+            <soap:address location="http://localhost:9004/Rethwel"/>
+        </wsdl:port>
+        <wsdl:port binding="tns:Greeter_SOAPBinding" name="Gordy">
+            <soap:address location="https://localhost:9001/Gordy"/>
+        </wsdl:port>
+        <wsdl:port binding="tns:Greeter_SOAPBinding" name="Bethal">
+            <soap:address location="https://localhost:9002/Bethal"/>
+        </wsdl:port>
+        <wsdl:port binding="tns:Greeter_SOAPBinding" name="Hurlon">
+            <soap:address location="http://localhost:9006/Hurlon"/>
+        </wsdl:port>
+        <wsdl:port binding="tns:Greeter_SOAPBinding" name="Poltim">
+            <soap:address location="https://localhost:9005/Poltim"/>
+        </wsdl:port>
+        <wsdl:port binding="tns:Greeter_SOAPBinding" name="Abost">
+            <soap:address location="https://localhost:9007/Abost"/>
+        </wsdl:port>
+        <wsdl:port binding="tns:Greeter_SOAPBinding" name="Morpit">
+            <soap:address location="https://localhost:9008/Morpit"/>
+        </wsdl:port>
+    </wsdl:service>
+</wsdl:definitions>

Reply via email to