# WSDL, Apache CXF und soapUI



## zzuegg (25. Jun 2012)

Hallo miteinander. 
Zur Betriebsführung mache ich mir gerade ein Programm welches die Daten direkt zur Hauptverwaltung sendet. Die Vewaltung war auch so nett eine SOAP Schnittstelle zur Verfügung zu stellen. Leider bin ich ein totaler SOAP anfänger.

Der Start war recht einfach, und die ersten Interaktionen (Login/Logout) funktionierten tadellos. 

Leider gingen die interaktionen mit komplexeren rückgaben nichtmehr. Nach etlichen vesuchen mit AXIS, CFX und so weiter bin ich nun bei einer konfiguration gelandet welcher mir vom Handling am besten zusagt. 

Mit dem Netbeans plugin swingUI kann man sich wunderbaren CFX code generieren welcher sich dann einfach nutzen lässt. 

Leider funktionieren auch hier die Abfragen mit komplexeren rückgabewerten nicht. 

Die Abstraktion der daten funktioniert leider nur bis zu einem bestimmten Bereich. Danach bekomme ich nur noch leere Objecte anstatt 'vollen' klassen. 

Mittlerweile gehe ich davon aus dass die WSDL datei nicht vollständig ist. 
Das Problem besteht darin dass einige Datentypen in einer separaten .xsd datei zu finden sind, diese Datei wird jedoch nirgens in der WSDL referenziert. 

Ist meine Annahme korreckt? Und wenn ja gibt es eine Möglichkeit das Problem einigermasen sauber zu lösen? 

WSDL+beispiel .xsd hier auf pastebin, da der text sonst zu lang für einen Post wird: -> [XML] WSDL: [XML] <?xml version="1.0" encoding="utf-8"?> <wsdl:definitions xmlns:so - Pastebin.com

Danke schon mal im voraus für Eure hilfe. 

Michael


----------



## DerFeivel (26. Jun 2012)

Bei welchen der Elemente aus der XSD bist du denn der Meinung, dass sie fehlen?


Ich habe mit hier gerade mit _wsimport -extension_ die Artefakte generiert und zumindest dabei hat er nichts fehlendes bemängelt. 

Hast du die XSD auch von der Verwaltung bekommen?


----------



## zzuegg (26. Jun 2012)

DerFeivel hat gesagt.:


> Bei welchen der Elemente aus der XSD bist du denn der Meinung, dass sie fehlen?
> 
> 
> Ich habe mit hier gerade mit _wsimport -extension_ die Artefakte generiert und zumindest dabei hat er nichts fehlendes bemängelt.
> ...



Hallo, erstmal vielen dank fuer die Antwort.
Ja, die XSD kommt auch von der Verwaltung.

Das problem scheint, dass die XSD nicht mit der WDSL verbunden ist, der aufruf 'getStammdaten' sollte eine rueckgabe vom typ 'Stammdaten' (definieiert in der XSD) bringen. Die rueckgabe der funktion ist in der wsdl jedoch nur als complextype/any definiert ohne referenz zur XSD.

Der generierte code liefert bei 'getStammdaten' nur eine List(Object) mit einem 'null' element.


----------



## DerFeivel (26. Jun 2012)

Also fehlt doch nichts .


Nein, keine Ahnung. Vielleicht hat der jeweilige Verantwortliche die XSD auch nur dazu benutzt, sich über jaxb Domainobjekte zur leichteren Handhabung zu generieren.
Ich finde die Schnittstelle eh irgendwie nur mäßig gut definiert (vom allgemeinen Entwurf abgesehen, bevorzuge ich bspw. zum Fehlerhandling noch so etwas wie ServiceFaults). 

Von daher solltest du dir vielleicht von der Verwaltung mal Daten geben lassen, die auf jeden Fall funktionieren.
Mit diesen Daten stellst du dann erstmal Anfragen mit SoapUI um erstmal ein Gefühl für den allgemeinen Ablauf zu bekommen (ohne cxf und netbeans).


----------



## zzuegg (26. Jun 2012)

DerFeivel hat gesagt.:


> Also fehlt doch nichts .
> 
> 
> Nein, keine Ahnung. Vielleicht hat der jeweilige Verantwortliche die XSD auch nur dazu benutzt, sich über jaxb Domainobjekte zur leichteren Handhabung zu generieren.
> ...



Naja die Fehlercodes sind schon definiert, nur wieder in einer separaten xsd datei, welche nicht referenziert wird. 
Ich habe funktionierende Date, die manuelle XML übertragung funktioniert auch einwandfrei, jedoch kann ich mir keinen (funktionierenden) Service compilieren, da die rückgabewerte nicht definiert/referenziert sind. 
Als Lösung würde sich anbieten die WSDL so umzuschreiben dass die rückgabewerte definiert werden. (Einfach den xsd inhalt in den entsprechnenden Bereich kopieren?), oder wie gesagt die XML's manuell zu parsen. Natürlich möglich jedoch für die komplexeren daten sehr umständlich?

Was würdes du machen?


----------



## DerFeivel (26. Jun 2012)

Ich meinte nicht Fehlercodes sondern Faults (also quasi das Service-Pendant zu Exceptions) .

Wie sprichst du denn den Webservice an (also was machst du bei: "die manuelle XML-Übertragung funktioniert auch einwandfrei")?

Und kennst du die Laufzeitumgebung des Webservices? Applikationserver stellen normalerweise auch die jeweilige WSDL zum Endpunkt bereit. Von dieser kannst du dir dann auch die Artefakte für einen Client generieren.


----------



## zzuegg (26. Jun 2012)

DerFeivel hat gesagt.:


> Ich meinte nicht Fehlercodes sondern Faults (also quasi das Service-Pendant zu Exceptions) .
> 
> Wie sprichst du denn den Webservice an (also was machst du bei: "die manuelle XML-Übertragung funktioniert auch einwandfrei")?
> 
> Und kennst du die Laufzeitumgebung des Webservices? Applikationserver stellen normalerweise auch die jeweilige WSDL zum Endpunkt bereit. Von dieser kannst du dir dann auch die Artefakte für einen Client generieren.



Die oben gepostete WSDL wird vom Applikationsserver zur verfügung gestellt. Manuell heisst für mich, entweder mit einem simplen post request, oder über soapUI. 

Laufzeitumgegung kenne ich nicht. 

Das einzige problem welches ich glaube zu haben, ist dass in der WSDL, folgenes element:
[XML]
<s:element name="getStammdatenResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="getStammdatenResult">
              <s:complexType mixed="true">
                <s:sequence>
                  <s:any/>
                </s:sequence>
              </s:complexType>
            </s:element>
          </s:sequence>
        </s:complexType>
      </s:element>
[/XML]

definiert ist, leider funktioniert die umwandlung von <s:any/> nicht. Im endeffekt sollte hier nach meinem jetzigen verständniss (Was bezüglich SOAP nicht viel ist) sowas wie
[XML]
      <s:element name="getStammdatenResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="getStammdatenResult">
              <s:complexType mixed="true">
                <s:sequence>
                  <s:element minOccurs="0" maxOccurs="1" name="Stammdaten" type="m:Stammdaten"/>
                </s:sequence>
              </s:complexType>
            </s:element>
          </s:sequence>
        </s:complexType>
      </s:element>
[/XML]

stehen, mit bezug zum element stammdaten aus der xsd. 
Leider finde ich gerade auch keinen weg um die XSD einzubinden, habe es mit 
[XML]
xmlns:m="https://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/stammdaten.xsd"
[/XML]
im header versucht. Jedoch bleibt m:Stammdaten nicht gültig...


----------



## DerFeivel (26. Jun 2012)

Also bei mir generiert er die Artefakte und - wie ich meine - auch richtig.

Aus 

[XML]            <s:element minOccurs="0" maxOccurs="1" name="massnahmen">
              <s:complexType mixed="true">
                <s:sequence>
                  <s:any />
                </s:sequence>
              </s:complexType>
            </s:element>
[/XML]

generiert er dann eine innere Klasse Massnahmen über deren Methode _getContent()_ ich dann auf eine Liste von Object zugreifen kann.


Ich vermute wie - glaube ich - schonmal sagte, dass der jeweilige Entwickler sich über JAXB aus der XSD die Objekte separat generiert. Da die Liste ja Objekte vom Typ Object entgegennimmt, kann er diese dann auch über den Webservice versenden und empfangen.


Möchtest du konsistent zu seiner Implementierung bleiben. Machst du es genauso.

Wenn du eine saubere Lösungen haben willst, solltest du dir:

How to Import XSD Into WSDL | eHow.com 

ansehen und der Hausverwaltung einen Gang einlegen


----------



## zzuegg (26. Jun 2012)

DerFeivel hat gesagt.:


> Also bei mir generiert er die Artefakte und - wie ich meine - auch richtig.
> 
> Aus
> 
> ...



Hallo, das erzeugen der klassen mit jaxb hat wunderbar funktioniert.
Bis zum getContent() bin isch schon immer gekommen. Leider habe ich angenommen dass es da ein getStammdaten() braucht.

Mein neues problem, wie wandle die List<Object> von getContent() in mein gewünschtes object um?

mit folgendem code:


```
XWSNutriExchangeServiceSoap client = new XWSNutriExchangeService().getXWSNutriExchangeServiceSoap12();
            
            String ticket=client.logIn("dummyUser", "dummyPassword", "dummySwKey");
            System.out.println(ticket);
            List<Object> objects=client.getStammdaten(ticket).getContent();
            List<Stammdaten> stammdaten=new ArrayList<Stammdaten>();
            for(Object o:objects){
                stammdaten.add((Stammdaten)o);
            }
```
bekommen ich immer eine cast exception:


```
26.06.2012 21:06:55 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL
INFO: Creating Service {http://localhost/nutriWebServices/v0003}XWSNutriExchangeService from WSDL: [url]https://www.betriebsheft.vip.coop/release/nutriwebservices/v0003/NutriExchangeService.asmx?WSDL[/url]
32010dd0-e4e8-4e63-8492-37dc7943a0d4
Exception in thread "main" java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast to Applications.ZAppStammdaten.Data.Stammdaten.Stammdaten
	at Executables.Test.VipSOAP_TEST.main(VipSOAP_TEST.java:41)
Java Result: 1
```


----------



## zzuegg (26. Jun 2012)

Vergiss den letzten post, ich muss natürlich den unmarshaller benützten. 

Funktioniert alles. Danke 1000mal für deine hilfe


----------

