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.