Avatar billede stephanryer Nybegynder
30. september 2008 - 20:56 Der er 44 kommentarer og
1 løsning

Kald af webservice i java

Jeg har læst arne_v's artikel om webservices
Jeg har derudover googlet rundt i adskillige timer og forsøgt at kalde en webservice, men nu bliver jeg nød til at skrive denne tråd. Kan simpelthen ikke få det til at virke.

Jeg vil gerne kalde denne webservice: http://www.valil.com/ChessWebService/Service.asmx

Jeg benytter eclipse og har inkluderet adskillige jars til mit project og min kode ser således ud:

public static void main(String[] args) {
String FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w - - 0 1";
String endpoint = "http://www.valil.com/ChessWebService/Service.asmx";
Call client;
try {
  client = new Call(endpoint);
  client.setOperationName(new QName("GetNextMove"));
  String ret = (String) client.invoke(new Object[] { FEN, "", 5 });
  System.out.println(ret);
} catch (MalformedURLException e) {
  e.printStackTrace();
} catch (RemoteException e) {
  e.printStackTrace();
}
}

Ved kørsel får jeg følgende fejl:

AxisFault
faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Client
faultSubcode:
faultString: Server did not recognize the value of HTTP Header SOAPAction: .
faultActor:
faultNode:
faultDetail:
    {http://xml.apache.org/axis/}stackTrace:Server did not recognize the value of HTTP Header SOAPAction: .
    at org.apache.axis.message.SOAPFaultBuilder.createFault(SOAPFaultBuilder.java:222)
    at org.apache.axis.message.SOAPFaultBuilder.endElement(SOAPFaultBuilder.java:129)
    at org.apache.axis.encoding.DeserializationContext.endElement(DeserializationContext.java:1087)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at javax.xml.parsers.SAXParser.parse(Unknown Source)
    at org.apache.axis.encoding.DeserializationContext.parse(DeserializationContext.java:227)
    at org.apache.axis.SOAPPart.getAsSOAPEnvelope(SOAPPart.java:696)
    at org.apache.axis.Message.getSOAPEnvelope(Message.java:435)
    at org.apache.axis.handlers.soap.MustUnderstandChecker.invoke(MustUnderstandChecker.java:62)
    at org.apache.axis.client.AxisClient.invoke(AxisClient.java:206)
    at org.apache.axis.client.Call.invokeEngine(Call.java:2784)
    at org.apache.axis.client.Call.invoke(Call.java:2767)
    at org.apache.axis.client.Call.invoke(Call.java:2443)
    at org.apache.axis.client.Call.invoke(Call.java:2366)
    at org.apache.axis.client.Call.invoke(Call.java:1812)
    at net.server.ai.AIMoveCalculator.main(AIMoveCalculator.java:19)

    {http://xml.apache.org/axis/}hostname:stephan

Server did not recognize the value of HTTP Header SOAPAction: .
    at org.apache.axis.message.SOAPFaultBuilder.createFault(SOAPFaultBuilder.java:222)
    at org.apache.axis.message.SOAPFaultBuilder.endElement(SOAPFaultBuilder.java:129)
    at org.apache.axis.encoding.DeserializationContext.endElement(DeserializationContext.java:1087)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at javax.xml.parsers.SAXParser.parse(Unknown Source)
    at org.apache.axis.encoding.DeserializationContext.parse(DeserializationContext.java:227)
    at org.apache.axis.SOAPPart.getAsSOAPEnvelope(SOAPPart.java:696)
    at org.apache.axis.Message.getSOAPEnvelope(Message.java:435)
    at org.apache.axis.handlers.soap.MustUnderstandChecker.invoke(MustUnderstandChecker.java:62)
    at org.apache.axis.client.AxisClient.invoke(AxisClient.java:206)
    at org.apache.axis.client.Call.invokeEngine(Call.java:2784)
    at org.apache.axis.client.Call.invoke(Call.java:2767)
    at org.apache.axis.client.Call.invoke(Call.java:2443)
    at org.apache.axis.client.Call.invoke(Call.java:2366)
    at org.apache.axis.client.Call.invoke(Call.java:1812)
    at net.server.ai.AIMoveCalculator.main(AIMoveCalculator.java:19)

Er der nogen, der ved, hvad jeg gør galt? Er ved at få grå hår over java vs kald til webservices :)

På forhånd tak.
Avatar billede arne_v Ekspert
30. september 2008 - 21:04 #1
Mit gæt er at det er en af de sædvanelige "der er 1000 forskellige kombinationer
af standarder - i den anden ende bruger de en og du bruger en anden".

Prøv og lad Axis generere en stub fremfor selv at kode kaldet. Det løser næsten altid
problemet.
Avatar billede arne_v Ekspert
30. september 2008 - 21:05 #2
Altså enten WSDL2Java i en bat fil *eller* samme via ant (bruger jeg altid selv) *eller*
installere web service modulerne i Eclipse og lad Eclipse gøre det samme.
Avatar billede stephanryer Nybegynder
30. september 2008 - 21:07 #3
jeg troede fidusen ved web services var ens standarder, men hvordan genererer jeg en automatisk stub? Sådan i praksis - skåret ud i pap :)
Avatar billede arne_v Ekspert
30. september 2008 - 21:14 #4
i artiklen gå ned til sektionen "client med genereret stub"
Avatar billede arne_v Ekspert
30. september 2008 - 21:14 #5
java -classpath axis.jar;commons-logging.jar;log4j-1.2.8.jar;commons-discovery.jar;wsdl4j.jar;jaxrpc.jar;saaj.jar org.apache.axis.wsdl.WSDL2Java http://localhost:8080/axis/services/SortService?wsdl

som command line
Avatar billede stephanryer Nybegynder
30. september 2008 - 21:14 #6
oki, kigger lige.
Avatar billede arne_v Ekspert
30. september 2008 - 21:15 #7
en ant snippet som jeg har brugt:

<project name="test" default="testrun">
    <path id="axis.classpath">
        <fileset dir="/Jakarta/Axis-1_4/lib">
            <include name="**/*.jar"/>
        </fileset>
    </path>
    <taskdef resource="axis-tasks.properties" classpathref="axis.classpath"/>
    <target name="stubgen">
        <axis-wsdl2java output="." url="http://localhost/SimpleTest.asmx?WSDL"/>
    </target>
    <target name="testbuild" depends="stubgen">
        <javac classpathref="axis.classpath" srcdir="." destdir="."/>
    </target>
    <target name="testrun" depends="testbuild">
        <java fork="yes" classpathref="axis.classpath" classpath="." classname="Test"/>
    </target>
    <target name="testmanualrun" depends="testbuild">
        <java fork="yes" classpathref="axis.classpath" classpath="." classname="TestManual"/>
    </target>
</project>
Avatar billede arne_v Ekspert
30. september 2008 - 21:21 #8
der er standarder som er ens i Java og .NET og Python og ...

men det er standarder ikke standard

SOAP 1.1 versus SOAP 1.2

styles: RPC/encoded, RPC/literal, Document/literal, Document/literal wrapped

o.s.v.
Avatar billede stephanryer Nybegynder
30. september 2008 - 21:23 #9
Well, hvilken version af axis, skal jeg køre, for at eksemplet med genereret stub virker? Altså fra denne side: http://ws.apache.org/axis/
Avatar billede arne_v Ekspert
30. september 2008 - 21:27 #10
bare tag nyeste (1.4)

så vil jeg tro at det virker med stub

hvis ikke - så må jeg lige selv prøve
Avatar billede stephanryer Nybegynder
30. september 2008 - 21:33 #11
Det har jeg prøvet og der får jeg beskeden, at filen DiscoverSingleton ikke kan findes.
(Omdøbte filnavnet til commons-loggin.jar til commons-loggin-1.4.0.jar, da det er hvad den hedder i version 1.4, men kan simpelthen ikke få det tl at virke.

Er rystet over, at det kan være så bøvlet at få det til at virke i java, når det er fikset på 1min i .net :)
Avatar billede stephanryer Nybegynder
30. september 2008 - 21:56 #12
Har fundet det her link, som påstår, at der er en bux i axis:

http://bytes.com/forum/thread758986.html

Men jeg kan ikk egennemskue, hvlke værdier jeg skal angive, som de forskellige strings.
Avatar billede arne_v Ekspert
30. september 2008 - 21:56 #13
Put alle jar filerne i din Axis versions lib dir i classpath.
Avatar billede arne_v Ekspert
30. september 2008 - 21:58 #14
Du kan altid manuelt skrive den samme kode som WSDL2Java genererer - men hvorfor dog
bruge tid på at finde ud af den slags.
Avatar billede arne_v Ekspert
30. september 2008 - 22:01 #15
Når du har fået det til at virke, så er det såmænd lige så nemt i Java som i .NET.

Problemet er at få det konfigureret.

Med .NET er det nemt. Du har har 1 valg mulighed: det web service stuff der kommer
med frameworket og det installeres under installationen af .NET. Done.

Med Java er der nogle standarder JAX-RPC, JAX-WS etc. og forskellige implementationer
Axis, Axis2, CXF etc.. SÅ skal du selv vælge en implementation og selv få alt installeret
i classpath.
Avatar billede stephanryer Nybegynder
30. september 2008 - 22:09 #16
Når jeg kører følgende:

java -classpath axis.jar;axis-ant;commons-discovory-0.2.jar;commons-logging-1.0.4.jar;log4j-1.2.8.jar;wsdl4j-1.5.1.jar;jaxrpc.jar;saaj.jar org.apache.axis.wsdl.WSDL2Java http://www.valil.com/ChessWebService/Service.asmx

Får jeg stadig fejlen, at følgende klassen ikke kan findes:
org/apache/commons/discovery/tools/DiscovorySingletong

Alle filerne i listen er præcis dem, som ligger i lib i axis 1.4
Avatar billede stephanryer Nybegynder
30. september 2008 - 22:09 #17
*org/apache/commons/discovery/tools/DiscovorySingleton
Avatar billede stephanryer Nybegynder
30. september 2008 - 22:21 #18
Jeg har forsøgt at følge debuggingen i forbindelse med den manuelle, og er kommet frem til følgende:

try {
            String FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w - - 0 1";
            String endpoint = "http://www.valil.com/ChessWebService/Service.asmx";
            Service service = new Service();
            Call call = (Call) service.createCall();

            call.setProperty(Call.SOAPACTION_USE_PROPERTY, new Boolean(true));
            call.setProperty(Call.SOAPACTION_URI_PROPERTY, "http://www.valil.com/ChessWebService/GetNextMove");

            call.setTargetEndpointAddress(new java.net.URL(endpoint));
            call.setOperationName(new QName("http://www.valil.com/ChessWebService/GetNextMove", "GetNextMove"));

            String ret = (String) call.invoke(new Object[] { FEN, "", 3 });
            System.out.println("Sendte " + FEN);
            System.out.println("Modtog " + ret);
        } catch (Exception e) {
            e.printStackTrace();
        }

Dette giver udskriften:

Sendte rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w - - 0 1
Modtog null


Der kastes altså ingen exception her, men der modtages null, hvilket jo naturligvis ikke er meningen.

Når jeg kalder samme webservice med de samme tre argumenter fra .net, får jeg et træk tilbage med syntaksen "e2e4", så jeg ved, at det skal kunne lade sig gøre at kalde med præcis de parametre.

Hvis du er ved at undersøge genereringen af stubben, så se bare bort fra denne besked. :)
Avatar billede arne_v Ekspert
30. september 2008 - 22:24 #19
Lidt mystisk med den klasse.

Jeg har:

C:\Jakarta\axis-1_4\lib>jar tvf commons-discovery-0.2.jar | grep DiscoverSingleton
  4216 Mon Apr 14 11:04:46 EDT 2003 org/apache/commons/discovery/tools/DiscoverSingleton.class
Avatar billede arne_v Ekspert
30. september 2008 - 22:25 #20
Prøv lige og jag den klasse lidt. Den skal kunne findes.
Avatar billede stephanryer Nybegynder
30. september 2008 - 22:33 #21
jeg har ikke apache. Kan den være kommet med det?
Avatar billede stephanryer Nybegynder
30. september 2008 - 22:37 #22
underligt - jeg har prøvet både med commons-discovery-0.2.jar, commons-discovery-0.4.jar og commons-discovery.jar nu og den kommer stadig med samme besked.
Avatar billede arne_v Ekspert
30. september 2008 - 22:41 #23
Angiver du rigtigt dir til alle jar filerne ?
Avatar billede arne_v Ekspert
30. september 2008 - 22:44 #24
Nej - du behøver ikke at have Tomcat installeret for at bruge Axis.
Avatar billede stephanryer Nybegynder
30. september 2008 - 22:52 #25
Ja, jeg kalder dem fra en .bat filer, der ligger i samme mappe som alle jar-filerne.

Mht den læsning, der giver mig null, så er det som om, der er forbindelse på en eller anden måde. Jeg får godt nok null tilbage, ligemeget hvor mange parametre jeg giver med. Kode:

try {
            String FEN = "rn1qk1nr/ppp1bppp/8/3pp3/P5bP/4P2N/1PPP1PP1/RNB1KB1R b - - 2 5";
            String endpoint = "http://www.valil.com/ChessWebService/Service.asmx";

            Service service = new Service();
            Call call = (Call) service.createCall();

            //call.setProperty(Call.SOAPACTION_USE_PROPERTY, new Boolean(true));
            //call.setProperty(Call.SOAPACTION_URI_PROPERTY, "http://www.valil.com/ChessWebService/GetNextMove");
           
            call.setTargetEndpointAddress(new java.net.URL(endpoint));
            call.setOperationName(new QName("GetNextMove"));
            call.setSOAPActionURI("http://www.valil.com/ChessWebService/GetNextMove");
            Object ret = call.invoke(new Object[] { FEN, "", new Integer(4) });

            System.out.println(ret);
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println(e.toString());
        }

Ved kørsel, udskrives blot: null

Hvis jeg ændrer

call.setSOAPActionURI("http://www.valil.com/ChessWebService/GetNextMove");

til

call.setSOAPActionURI("http://www.valil.com/ChessWebService/GetNextMove_TEST");

så får jeg en exception: Server did not recognize the value of HTTP Header SOAPAction: http://www.valil.com/ChessWebService/GetNextMove_TEST.

Det tyder altså på, at noget i ovenstående kode er rigtigt nok. Kan bare ikke gennemskue, hvad der skal til få at det kommer til at virke helt.
Avatar billede arne_v Ekspert
30. september 2008 - 23:00 #26
At bat filen ligger i samme dir som jar filerne får altså ikke dir til at passe.
Avatar billede arne_v Ekspert
30. september 2008 - 23:01 #27
Medmindre du kører jar mens du står i det dir.
Avatar billede stephanryer Nybegynder
30. september 2008 - 23:02 #28
jeg kører batch-filen fra det dir - så skulle det vel fungere? Eller hvad?
Avatar billede stephanryer Nybegynder
30. september 2008 - 23:09 #29
Men har du mulighed for at generere den stub egentlig? Så kunne det være jeg kunne bruge den efterfølgende.
Avatar billede arne_v Ekspert
30. september 2008 - 23:25 #30
Jeg er sikker på at du vil finde dette her morsomt.

:-)

commons-discovory-0.2.jar
->
commons-discovery-0.2.jar
Avatar billede arne_v Ekspert
30. september 2008 - 23:26 #32
så får jeg en stub
Avatar billede stephanryer Nybegynder
30. september 2008 - 23:30 #33
Kan ikke få det til at virke.

Hvad mener du med


commons-discovory-0.2.jar
->
commons-discovery-0.2.jar

? :)
Avatar billede arne_v Ekspert
30. september 2008 - 23:31 #34
ret stave fejlen
Avatar billede stephanryer Nybegynder
30. september 2008 - 23:34 #35
OMG! Så kører det :)

Jeg har fået 5 filer genereret nu. Hvad kalder jeg så af dem?
Avatar billede arne_v Ekspert
30. september 2008 - 23:42 #36
det plejer at være:

XxxxLocator serv = new XxxxTestLocator();
XxxxSoap soap = serv.getXxxxSoap();
// kald soap.whatever(bla,bla)
Avatar billede stephanryer Nybegynder
30. september 2008 - 23:42 #37
Nu har jeg hevet alle fem klasser ind i mit projekt. Når jeg kører følgende:

try {
            ServiceSoapStub stub = new ServiceSoapStub();
            String boardFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w - - 0 1";
            stub.getNextMove(boardFEN, "", 4);
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println(e.toString());
        }

...Får jeg denne exception:

AxisFault
faultCode: {http://xml.apache.org/axis/}Server.NoEndpoint
faultSubcode:
faultString: No endpoint
faultActor:
faultNode:
faultDetail:
    {http://xml.apache.org/axis/}exceptionName:org.apache.axis.NoEndPointException
    {http://xml.apache.org/axis/}stackTrace:No endpoint
    at net.server.ai.webservice.ServiceSoapStub.getNextMove(ServiceSoapStub.java:102)
    at net.server.ai.AIMoveCalculator.main(AIMoveCalculator.java:11)

    {http://xml.apache.org/axis/}hostname:stephan

No endpoint
    at net.server.ai.webservice.ServiceSoapStub.getNextMove(ServiceSoapStub.java:102)
    at net.server.ai.AIMoveCalculator.main(AIMoveCalculator.java:11)
No endpoint
Avatar billede arne_v Ekspert
30. september 2008 - 23:42 #38
stubben skal naturligvis compiles og client skal importere package, men ...
Avatar billede arne_v Ekspert
30. september 2008 - 23:47 #39
prøv lige med serv og soap som jeg beskrev
Avatar billede arne_v Ekspert
30. september 2008 - 23:48 #40
ServiceLocator serv = new ServiceLocator();
ServiceSoap soap = serv.getServiceSoap();
String boardFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w - - 0 1";
soap.getNextMove(boardFEN, "", 4);
Avatar billede stephanryer Nybegynder
30. september 2008 - 23:51 #41
YES YES YES !!!!!!!!

Har nu brugt over 12 klamme timer på det og så virker det - takket være dig
Jeg vil endnu engang takke mange gange for din vedvarende hjælp. Læg et svar :)

Kan for god ordens skyld lige sige, at der kan kaldes således:

String boardFEN = "...";
            ServiceLocator locator = new ServiceLocator();
            ServiceSoap soap = locator.getServiceSoap();
            String result = soap.getNextMove(boardFEN, "", 4);
            System.out.println(result);

Læg et svar :D
Avatar billede arne_v Ekspert
01. oktober 2008 - 00:27 #42
svar
Avatar billede arne_v Ekspert
01. oktober 2008 - 00:29 #43
Hvis du er vant til at bruge ant så er det nemmere:

    <path id="axis.classpath">
        <fileset dir="/Jakarta/Axis-1_4/lib">
            <include name="**/*.jar"/>
        </fileset>
    </path>
    <taskdef resource="axis-tasks.properties" classpathref="axis.classpath"/>
    <target name="stubgen">
        <axis-wsdl2java output="." url="http://localhost/SimpleTest.asmx?WSDL"/>
    </target>

fordi der kan man angive alle jar filer i et dir (tja - det kan jo også i Java 1.6 nu)
Avatar billede arne_v Ekspert
01. oktober 2008 - 00:29 #44
Og med det rigtige Eclipse plugin installeret så er det bare at køre en wizard og
give den URL på WSDL og så laver den det hele (også ved hjælp af Axis !)
Avatar billede stephanryer Nybegynder
01. oktober 2008 - 10:35 #45
Well nu gemmer jeg den batch-fil og så smækker jeg alle de jars ind i en samlet. Så er det ikke så bøvlet for fremtiden :)

Mange tak for hjælpen.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester