English 中文(简体)
Eclipse Generated Web Service Client Extremely Slow
原标题:

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 &quot;print 5&quot;</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.

最佳回答

1) Verify that the C# and Java clients are sending exactly the same requests to the server. If you re using Jetty, turning on request logging would probably give you the data that you need.

2) Once the SAX parser starts running on the client, it s going to make callbacks that will wind up -- directly or indirectly -- invoking methods in your generated client. You should be able to set breakpoints at the beginning and end (and/or returns) of the generated client methods, and use these to determine where the delay[s] happen[s].

(BTW, in the SAX API, URLs such as http://xml.org/sax/properties/lexical-handler are used locally to identify property names; nothing is going to look for anything at that address. See http://xerces.apache.org/xerces2-j/properties.html for more info.)

问题回答

I got the same problem and solved it modifying the http version.

A simpler way to to that is, inside the stub class, calling the setProperty method on the Call instance:

_call.setProperty(MessageContext.HTTP_TRANSPORT_VERSION,HTTPConstants.HEADER_PROTOCOL_V11);

Your problem is exactly what I m facing now. And funny, I ve gone through pretty much the same cycle (of the endpoint service, .net client working fine, and eclipse generated client taking a good 5 minutes to process). Thank you, indeed, for posting the updates and the solution. I m not a java savvy, so may I ask if you applied the solution to the same eclipse generated client code? Or did you do something completely different? If you have modified the eclipse generated client code, where exactly have you added those lines?

Thanks, and and I really appreciate the help :)

Cheers, Arash

Most likely a timeout. Could be that parser trying to download something from internet (DTD, XSD, etc) but you re behind a proxy/firewall.

Try to take stack trace of the server, when running the test to see what s going on (e.g. jps/ jstat).





相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签