Klassen via JAXB erfolgreich generiert, wie geht es nun weiter?

Abend ...

Zuerst muss ich leider zugeben, dass dies mein erstes "Ich spreche mit externen WebServices Projekt" ist
... daher stehe ich ein wenig auf dem Schlauch und freue mich über jegliches Feedback ;)

Ziel ist es eine externe API anzubinden, für welche ich mir bereits mit dem "maven-jaxb2-plugin" alle notwendigen Klassen generiert habe. Als weiterer Schritt folgt nun die Kommunikation mit dem externen Service und genau hier brauche ich Unterstützung ...

Es muss nun ...
  • ein Login stattfinden (via Login-Object)
  • danach muss eine weitere Foobar-Methode mit zwei Übergabeparametern (String, String) ausgeführt werden

Nach einigen Tutorials habe ich ein wenig mit "JAXBContext.newInstance()" rumgespielt und mit Hilfe der "Marshaller" erfolgreich ein XML-Dump in der Konsole (Eclipse) erzeugt. An dieser Stelle komme ich nun nicht mehr weiter, da ich mir folgende Fragen stelle: wie sende ich das mit Hilfe des JAXBContext erzeugte Objekte an die externe API?


Ich würde mich daher über einige Tipps, gerne auch einfach etwas DummyCode freuen.

Frohes Schaffen & schones WE!

Gruß,
Luke
 

DerFeivel

Bekanntes Mitglied
Verstehe ich die Aufgabenstellung richtig, dass du einen externen Webservice ansprechen möchtest, dessen Schnittstelle dir über eine WSDL/einen WSDL-Endpunkt gegeben ist?

Hierfür verwendet man eigentlich das jaxws-maven-plugin verwenden. Dieses generiert dir neben den Objekten die auch durch JaxB erzeugt werden zusätzlich noch Service-Artefakte, die du dann zum Aufruf deines Webservices verwenden kannst.
Wenn Webservice dann die generierte Klasse ist, welche 'Service' erweitert, dann kannst du deinen Webservice wie folgt aufrufen:


WebServices e = new WebServices();
WebServicesPortType port = e.getWebServicesEndpoint();

Rückgabeobjekt Webmethode = port.foobar(parameter1,parameter2);
 
Vielen Dank für die Antwort.

Deine Annahme ich vollkommen richtig, d.h. mir liegt ein ganzes WSDL-Paket vor und weiterhin stehen mir sämtliche Zugangsdaten (Login + Zugriff auf Sandbox) zur Verfügung.

Bevor ich die Klassen mit dem maven-jaxb2-plugin generiert habe, habe ich noch das jaxws-maven-plugin ausprobiert. Leider bekomme ich bei Ubuntu (11.04) und Eclipse (3.6.X) den bekannten "execution" / "lifecycle" Fehler. Auch diverse Bugfixes (m2-connector oder WTP Plugin nachinstallieren) haben dies nicht beheben können.... aber dies ist noch ein ganz anderes Problem ;)

Sollte es also mit jaxws-maven-plugin beim zweiten Anlauf klappen, so werde ich die WebService-Klassen direkt ansprechen.


Momentan gehe ich jedoch davon aus, dass ich 2-3 einzelne Service-Calls in einer Method in bestehenden Beans zusammenfassen werde, da die Schnittstellendefinition für eine logische Operation genau diese 2-3 Calls vorsieht.

Daher vllt. noch die Frage: Wie muss ich die aus JAXB2 generierten Klassen in einem Service verpacken und diese an die externe Schnittstelle senden?

Momentan gehe ich ca. vom dem folgenden Schnipsel aus ...
Java:
@WebService
public class FooBarService
{
   @WebMethod
   public String doSomething(@WebParam(name = "foo") String foo, @WebParam(name = "bar") String bar)
   {
      return "foo bar baz ... ";
   }
}

Ist das richtig?


Danke & Gruß,
Luke
 

DerFeivel

Bekanntes Mitglied
Puhh.


Auf Ubuntu habe ich schon lang nix mehr gemacht. Daher sagt mir auch der 'berühmte' Lifecycle Execution-Fehler nicht viel.
Einen Umweg über Jaxb musste/habe ich daher auch nie probiert/probieren müssen.



Nen Workaround der mir gerade einfällt wäre noch, dass du dir die Service-Artefakte über wsimport per Hand erstellst und den Quellcode in ein separates Projekt verpackst. Dieses kannst du dann ja über Maven wieder als Abhängigkeit für dein eigenes Projekt verwenden.


Nicht schön, aber selten.


@Deinem Code:


Die Annotationen sind für die Service-Seite und nicht für den Aufruf gedacht.
 
Nochmals... vielen Dank für die Antwort :)
Es sah eigentlich ganz gut aus, jedoch habe ich ein Problem mit der Session.

Kurz vorab ...
  • Nach Anmeldung am Service wird eine JSESSIONID geschrieben, welche ich z.B. in soapUI sehe.
  • Beim Aufruf einer folgenden Funktion wird stets bemängelt, dass ich mich anmelden muss, d.h. Session ist weg.

Mein Testclient (eine Bean) mit welchem ich eine einfache Methode zum Prüfen der Verbindung aufrufe, sieht wie folgt aus.
Java:
@Stateful
@LocalBean
@Pool(maxSize = 500, timeout = 50000, value = PoolDefaults.POOL_IMPLEMENTATION_STRICTMAX)
public class SoapTestBean
{
	// main api class providing needed method instances (ports, endpoints, etc.)
	SoapAPI soapInstance = new SoapAPI();
		
	TestCaseRequest testRequest = new TestCaseRequest();
	testRequest.setKey( "foo, bar, baz ..." );
	testRequest.setValue( "quux, quuux ..." );

	// authentication
	soapInstance.getLogin().login( "username", "password" );

	// get result ...
	TestCaseResponse testResponse = soapInstance.getTestCase( testRequest );
}

Ich habe angenommen, dass beim Aufruf des Login und anschließendem Aufruf einer API Methode, diese stets die Session kennen wird. Leider ist dies nicht der Fall ... und ich bekomme Exception geworden mit dem Hinweis "Bitte anmelden".
Hier noch die wichtigsten SOAP Klassen, generiert mit wsimport.

Die Hauptklasse, welche mir sämtliche API Methoden kapselt und zur Verfügung stellt.
Java:
@WebServiceClient(name = "SoapAPI", targetNamespace = "localhost/foo/bar/wsdl", wsdlLocation = "localhost/foo/bar/my.wsdl")
public class SoapAPI extends Service
{
	// ... bla
	@WebEndpoint(name = "Login")
	public Login getLogin() {
		return super.getPort( new QName("localhost/foo/bar/wsdl", "Login"), Login.class);
	}
	// ... bla
}

Die Login-Klasse mit der void-Methode login() sieht wie folgt aus.
Java:
@WebService(name = "Login", targetNamespace = "localhost/foo/bar/wsdl/auth")
@XmlSeeAlso({
	com.my.foo.bar.wsdl.schemas.login.ObjectFactory.class
})
public interface Login {

	@WebMethod(operationName = "login", action = "localhost/foo/bar/wsdl/auth/Login")
	@RequestWrapper(localName = "login", targetNamespace = "localhost/foo/bar/wsdl/schemas/auth", className = "com.my.foo.bar.wsdl.schemas.Login")
	@ResponseWrapper(localName = "loginSuccess", targetNamespace = "localhost/foo/bar/wsdl/schemas/auth", className = "localhost/foo/bar/wsdl/voidInstance")
	public void login(
		@WebParam(name = "username", targetNamespace = "localhost/foo/bar/wsdl/schemas/auth") String user,
		@WebParam(name = "password", targetNamespace = "localhost/foo/bar/wsdl/schemas/auth") String password
	);
}

Ich hoffe die Klassenstruktur kann man verstehen.
Man kann den generierten Code eigentlich zusammenfassen ...
  • Es gibt eine Menge an Interfaces, welche meine Methoden sind
  • Die Hauptklasse (extends Service) bietet mit Methoden an, welche mir die Ports der Interfaces zurück geben ( super.getPort( Interface) )

Danke & Gruß,
Luke
 

DerFeivel

Bekanntes Mitglied
Nen zustandsbehafteter Soap-Webservice? :wuerg:


Nach kurzer Recherche musst du anscheinend deinem Client mitteilen, dass er die Session-Information die mit der Response mitkommt, speichern soll:

http://it.spsu.edu/research/Tech_Report/Kai_1.pdf


Also das hier einfügen, bevor du die login-Aufrufst:

Map requestContext = ((BindingProvider)soapInstance.getLogin()).getRequestContext();
requestContext.put(BindingProvider.SESSION_MAINTAIN_PROPERTY,true);
 
Habe ich bereits versucht, jedoch funktioniert dies nicht.
Es könnte an dem JBoss oder der Beans Konfiguration liegen... habe hier noch nicht sämtliche Optionen probiert.


Gibt es ein empfehlenswertes Eclipse View / Plugin mit welchem ich mir die Header anschauen kann?
Quasi... einfach mal prüfen ob die SessionId mitgesendet wird.

Danke & Gruß,
Luke
 
Sollte dieses Problem mal auftreten, empfehle ich dringendst euch den HttpResponse-Header anzusehen.
Meine Lösung des Problems war nämlich eine invalide PATH-Angabe im "Set-Cookie" Bereich :)

Ein andere Workaround wäre ...
  • HttpResponse-Header des Logins auswerten
  • "Set-Cookie" Values zwischenspeichern
  • Beim nächsten Request, den HttpRequest-Header manipulieren und als "cookie" Parameter die zwischengespeicherten "Set-Cookie" Werte (also JSessionId und Path) setzen

Den Workaround habe ich nicht explizit getestet, ich kann mir aber vorstellen, dass es hierbei zu Problemen beim Zugriff auf die MessageContext-Instanzen (ResponseContext und RequestContext) kommt. Wenn man aber den Port / Service in einen BindingProvider-Typ umwandeln könnte, hat man die Möglichkeit getRequestContext() / getResponseContext zu benutzen ;)

Dokumentation: BindingProvider (Java Platform SE 6)

Gruß,
Luke
 

Ähnliche Java Themen

Neue Themen


Oben