A little up front info:
I have a SOAP service (hosted using JAX-WS (Endpoint class), but I don't think that is important).
I can connect to and use the web service just fine with Visual Studio generating the client (C#).
I generated a java client using Eclipse Web Tools (new --> other --> web services --> web services client).
Then I wrote a JUnit test to test the client. The test passes, but it takes an extremely long time to run. Each service call takes 300 seconds (give or take a couple seconds). Furthermore, it doesn't matter how fast the computer is. If I run this on my very slow work laptop it takes the same amount of time as if I run it on my fast home machine.
I have debugged into the axis code to the following function within org.apache.axis.encoding.DeserializationContext:
public void parse() throws SAXException
{
if (inputSource != null) {
SAXParser parser = XMLUtils.getSAXParser();
try {
parser.setProperty("http://xml.org/sax/properties/lexical-handler", this);
parser.parse(inputSource, this);
try {
// cleanup - so that the parser can be reused.
parser.setProperty("http://xml.org/sax/properties/lexical-handler", nullLexicalHandler);
} catch (Exception e){
// Ignore.
}
no suprise, but the call to parser.parse() is taking up the 300 seconds. The from the web service is very short, so it shouldn't take much time to parse.
In case anyone is wondering, the actual type of parser is com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl
I can't debug into it because I don't have the source (and I'm tired up debugging 50 calls deep into commonly used libraries).
I'm currently running the profiler to include packages from Sun. I'll post my findings for that once it completes (adding all those packages significantly slows down the test)
I'm running Eclipse 3.5.1
and I'm using axis 1.4
Edit:
Here is the JUnit test:
@Test
public void testExecuter() throws IOException, InterruptedException, RemoteException, ServiceException
{
//Listener l = new Listener(3456);
//l.start();
Executer exec = new ExecuterServiceLocator().getExecuterPort();
//Executer exec = new ExecuterProxy("http://localhost:3456/Executer");
System.out.println("executer created");
_return remote = exec.execute("perl -e \"print 5\"", new EvAction[0]);
System.out.println("after call 1");
assertEquals("5", remote.getStdout());
assertEquals("", remote.getStderr());
assertEquals(0, remote.getReturnCode());
}
NOTE: Both ways of creating the Executer have the same thing happen
Edit2:
Here is the code I'm using to start the service:
public static void main(String[] args) {
Endpoint.create(new Executer()).publish("http://localhost:3456/Executer");
}
I can't post the URL since I am just developping it on a single machine right now. However, here is the WSDL that is generated if I go to http://localhost:3456/Executer?WSDL
<!--
Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.1.6 in JDK 6.
-->
−
<!--
Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.1.6 in JDK 6.
-->
−
<definitions targetNamespace="http://executer/" name="ExecuterService">
−
<types>
−
<xsd:schema>
<xsd:import namespace="http://executer/" schemaLocation="http://localhost:3456/Executer?xsd=1"/>
</xsd:schema>
</types>
−
<message name="Execute">
<part name="parameters" element="tns:Execute"/>
</message>
−
<message name="ExecuteResponse">
<part name="parameters" element="tns:ExecuteResponse"/>
</message>
−
<message name="IOException">
<part name="fault" element="tns:IOException"/>
</message>
−
<message name="InterruptedException">
<part name="fault" element="tns:InterruptedException"/>
</message>
−
<portType name="Executer">
−
<operation name="Execute">
<input message="tns:Execute"/>
<output message="tns:ExecuteResponse"/>
<fault message="tns:IOException" name="IOException"/>
<fault message="tns:InterruptedException" name="InterruptedException"/>
</operation>
</portType>
−
<binding name="ExecuterPortBinding" type="tns:Executer">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
−
<operation name="Execute">
<soap:operation soapAction=""/>
−
<input>
<soap:body use="literal"/>
</input>
−
<output>
<soap:body use="literal"/>
</output>
−
<fault name="IOException">
<soap:fault name="IOException" use="literal"/>
</fault>
−
<fault name="InterruptedException">
<soap:fault name="InterruptedException" use="literal"/>
</fault>
</operation>
</binding>
−
<service name="ExecuterService">
−
<port name="ExecuterPort" binding="tns:ExecuterPortBinding">
<soap:address location="http://localhost:3456/Executer"/>
</port>
</service>
</definitions>
Edit:
I think this might be causing a problem:
I used TCPMonitor to look at the SOAP requests and I noticed that the client was speaking HTTP/1.0 and the server is speaking HTTP/1.1, but I don't know if this is causing the problem. I'm currently trying to figure out how to make the client speak HTTP/1.1.
Here are the SOAP messages in case anyone was wondering:
POST /Executer HTTP/1.0
Content-Type: text/xml; charset=utf-8
Accept: application/soap+xml, application/dime, multipart/related, text/*
User-Agent: Axis/1.4
Host: USENBOONETL1C:2222
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: ""
Content-Length: 354
<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body><Execute xmlns="http://executer/"><arg0 xmlns="">perl -e "print 5"</arg0></Execute></soapenv:Body></soapenv:Envelope>
and the response:
HTTP/1.1 200 OK
Content-type: text/xml;
charset="utf-8"
Content-length: 266
<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:ExecuteResponse xmlns:ns2="http://executer/"><return><stdout>5</stdout><stderr></stderr><returnCode>0</returnCode></return></ns2:ExecuteResponse></S:Body></S:Envelope>
Edit:
Finally! turns out changing the HTTP client to CommonsHTTPClient and using HTTP/1.1 fixed the issue:
Here is the code I added to the client which fixed it:
BasicClientConfig basicClientConfig = new BasicClientConfig();
SimpleChain simpleChain = new SimpleChain();
simpleChain.addHandler(new CommonsHTTPSender());
basicClientConfig.deployTransport("http", simpleChain);
ExecuterServiceLocator l = new ExecuterServiceLocator(basicClientConfig);
...
note: You have to add common-httpclient.jar
and common.codec.jar
to the classpath.