Das Problem ist, dass ich einen Webdienst-Client aus einer Datei erstellen muss, die mir zur Verfügung gestellt wurde. Ich habe diese Datei auf dem lokalen Dateisystem gespeichert und solange ich die WSDL-Datei im richtigen Ordner des Dateisystems ablege, ist alles in Ordnung. Wenn ich die Datei auf einem Server einsetze oder die WSDL-Datei aus dem Dateisystemordner entferne, kann der Proxy die WSDL-Datei nicht finden und gibt einen Fehler aus. Ich habe das Web durchsucht und die folgenden Beiträge gefunden, aber ich habe es nicht hinbekommen, dass es funktioniert: https://stackoverflow.com/questions/764772/jax-ws-loading-wsdl-from-jar http://www.java.net/forum/topic/glassfish/metro-and-jaxb/client-jar-cant-find-local-wsdl-0 http://blog.vinodsingh.com/2008/12/locally-packaged-wsdl.html
Ich verwende NetBeans 6.1 (dies ist eine Legacy-Anwendung, die ich mit diesem neuen Web-Service-Client aktualisieren muss). Unten ist die JAX-WS Proxy-Klasse:
@WebServiceClient(name = "SOAService", targetNamespace = "http://soaservice.eci.ibm.com/", wsdlLocation = "file:/C:/local/path/to/wsdl/SOAService.wsdl")
public class SOAService
extends Service
{
private final static URL SOASERVICE_WSDL_LOCATION;
private final static Logger logger = Logger.getLogger(com.ibm.eci.soaservice.SOAService.class.getName());
static {
URL url = null;
try {
URL baseUrl;
baseUrl = com.ibm.eci.soaservice.SOAService.class.getResource(".");
url = new URL(baseUrl, "file:/C:/local/path/to/wsdl/SOAService.wsdl");
} catch (MalformedURLException e) {
logger.warning("Failed to create URL for the wsdl Location: 'file:/C:/local/path/to/wsdl/SOAService.wsdl', retrying as a local file");
logger.warning(e.getMessage());
}
SOASERVICE_WSDL_LOCATION = url;
}
public SOAService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public SOAService() {
super(SOASERVICE_WSDL_LOCATION, new QName("http://soaservice.eci.ibm.com/", "SOAService"));
}
/**
* @return
* returns SOAServiceSoap
*/
@WebEndpoint(name = "SOAServiceSOAP")
public SOAServiceSoap getSOAServiceSOAP() {
return super.getPort(new QName("http://soaservice.eci.ibm.com/", "SOAServiceSOAP"), SOAServiceSoap.class);
}
/**
* @param features
* A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values.
* @return
* returns SOAServiceSoap
*/
@WebEndpoint(name = "SOAServiceSOAP")
public SOAServiceSoap getSOAServiceSOAP(WebServiceFeature... features) {
return super.getPort(new QName("http://soaservice.eci.ibm.com/", "SOAServiceSOAP"), SOAServiceSoap.class, features);
}
}
Dies ist mein Code zur Verwendung des Proxys:
WebServiceClient annotation = SOAService.class.getAnnotation(WebServiceClient.class);
// trying to replicate proxy settings
URL baseUrl = com.ibm.eci.soaservice.SOAService.class.getResource("");//note : proxy uses "."
URL url = new URL(baseUrl, "/WEB-INF/wsdl/client/SOAService.wsdl");
//URL wsdlUrl = this.getClass().getResource("/META-INF/wsdl/SOAService.wsdl");
SOAService serviceObj = new SOAService(url, new QName(annotation.targetNamespace(), annotation.name()));
proxy = serviceObj.getSOAServiceSOAP();
/* baseUrl;
//classes\com\ibm\eci\soaservice
//URL url = new URL(baseUrl, "../../../../wsdl/SOAService.wsdl");
proxy = new SOAService().getSOAServiceSOAP();*/
//updating service endpoint
Map<String, Object> ctxt = ((BindingProvider)proxy ).getRequestContext();
ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192);
ctxt.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, WebServiceUrl);
NetBeans hat eine Kopie der WSDL in web-inf/wsdl/client/SOAService abgelegt, daher möchte ich sie nicht auch noch in META-INF hinzufügen. Die Serviceklassen befinden sich in WEB-INF/classes/com/ibm/eci/soaservice/ und die Variable baseurl enthält den vollständigen Pfad zum Dateisystem (c:\path\to\the\project...\soaservice ). Der obige Code löst den Fehler aus:
javax.xml.ws.WebServiceException: Der Zugriff auf die WSDL unter: file:/WEB-INF/wsdl/client/SOAService.wsdl ist fehlgeschlagen. Es ist fehlgeschlagen mit: \WEB-INF\wsdl\client\SOAService.wsdl (kann den Pfad nicht finden)
Soll ich also zunächst die wsdllocation der Proxyklasse aktualisieren? Wie sage ich dann der SOAService-Klasse in WEB-INF/classes/com/ibm/eci/soaservice, dass sie nach der WSDL in \WEB-INF\wsdl\client\SOAService.wsdl suchen soll?
EDITED: Ich habe diesen anderen Link gefunden - http://jianmingli.com/wp/?cat=41, der besagt, dass man die WSDL in den Klassenpfad einfügen soll. Ich schäme mich zu fragen: Wie kann ich sie in den Klassenpfad der Webanwendung einfügen?
Die beste Option ist die Verwendung von jax-ws-catalog.xml
Wenn Sie die lokale WSDL-Datei kompilieren, überschreiben Sie den WSDL-Speicherort und setzen ihn auf etwas wie
http://localhost/wsdl/SOAService.wsdl
Keine Sorge, es handelt sich nur um einen URI und nicht um eine URL, d.h. Sie müssen die WSDL nicht unter dieser Adresse verfügbar haben.
Sie können dies tun, indem Sie die Option wsdllocation an den wsdl-to-java-Compiler übergeben.
Dadurch ändert sich Ihr Proxy-Code von
static {
URL url = null;
try {
URL baseUrl;
baseUrl = com.ibm.eci.soaservice.SOAService.class.getResource(".");
url = new URL(baseUrl, "file:/C:/local/path/to/wsdl/SOAService.wsdl");
} catch (MalformedURLException e) {
logger.warning("Failed to create URL for the wsdl Location: 'file:/C:/local/path/to/wsdl/SOAService.wsdl', retrying as a local file");
logger.warning(e.getMessage());
}
SOASERVICE_WSDL_LOCATION = url;
}
in
static {
URL url = null;
try {
URL baseUrl;
baseUrl = com.ibm.eci.soaservice.SOAService.class.getResource(".");
url = new URL(baseUrl, "http://localhost/wsdl/SOAService.wsdl");
} catch (MalformedURLException e) {
logger.warning("Failed to create URL for the wsdl Location: 'http://localhost/wsdl/SOAService.wsdl', retrying as a local file");
logger.warning(e.getMessage());
}
SOASERVICE_WSDL_LOCATION = url;
}
Beachten Sie, dass file:// im URL-Konstruktor in http:// geändert wurde.
Jetzt kommt in jax-ws-catalog.xml. Ohne jax-ws-catalog.xml wird jax-ws in der Tat versuchen, die WSDL von dem Ort
http://localhost/wsdl/SOAService.wsdl zu laden.zu laden und scheitert, da keine solche WSDL verfügbar ist.
Aber mit jax-ws-catalog.xml können Sie jax-ws auf eine lokal verpackte WSDL umleiten, wenn es versucht, auf die WSDL @
http://localhost/wsdl/SOAService.wsdl.
Hier's jax-ws-catalog.xml
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system">
<system systemId="http://localhost/wsdl/SOAService.wsdl"
uri="wsdl/SOAService.wsdl"/>
</catalog>
Was Sie tun, ist jax-ws zu sagen, dass es, wenn es WSDL von
http://localhost/wsdl/SOAService.wsdl laden musslädt, soll es sie aus dem lokalen Pfad wsdl/SOAService.wsdl laden.
Wo sollten Sie nun wsdl/SOAService.wsdl und jax-ws-catalog.xml ablegen? Das ist die Millionen-Dollar-Frage, nicht wahr?
Sie sollten sich im META-INF-Verzeichnis Ihrer Anwendungs-Jar-Datei befinden.
also etwas wie dies
pre> ABCD.jar | META-INF | jax-ws-catalog.xml | wsdl | SOAService.wsdl
Auf diese Weise müssen Sie nicht einmal die URL in Ihrem Client überschreiben, die auf den Proxy zugreift. Die WSDL wird von Ihrem JAR abgerufen, und Sie müssen keine hart kodierten Dateisystempfade in Ihrem Code verwenden.
Weitere Informationen über jax-ws-catalog.xml http://jax-ws.java.net/nonav/2.1.2m1/docs/catalog-support.html
Ich hoffe, das hilft
Ein anderer Ansatz, den wir erfolgreich verfolgt haben, ist die Generierung des WS-Client-Proxy-Codes mit wsimport (aus Ant, als Ant-Task) und die Angabe des Attributs wsdlLocation.
<wsimport debug="true" keep="true" verbose="false" target="2.1" sourcedestdir="${generated.client}" wsdl="${src}${wsdl.file}" wsdlLocation="${wsdl.file}">
</wsimport>
Da wir dies für ein Projekt mit mehreren WSDLs ausführen, löst das Skript den Wert $(wsdl.file} dynamisch auf, der auf /META-INF/wsdl/IhrWebServiceName.wsdl relativ zum JavaSource-Speicherort (oder /src, je nachdem, wie Sie Ihr Projekt eingerichtet haben) eingestellt ist. Während des Build-Prozesses werden die WSDL- und XSD-Dateien an diesen Speicherort kopiert und in die JAR-Datei gepackt. (ähnlich der von Bhasakar oben beschriebenen Lösung)
MyApp.jar
|__META-INF
|__wsdl
|__YourWebServiceName.wsdl
|__YourWebServiceName_schema1.xsd
|__YourWebServiceName_schmea2.xsd
Hinweis: Stellen Sie sicher, dass die WSDL-Dateien relative Verweise auf importierte XSDs und keine http-URLs verwenden:
<types>
<xsd:schema>
<xsd:import namespace="http://valueobject.common.services.xyz.com/" schemaLocation="YourWebService_schema1.xsd"/>
</xsd:schema>
<xsd:schema>
<xsd:import namespace="http://exceptions.util.xyz.com/" schemaLocation="YourWebService_schema2.xsd"/>
</xsd:schema>
</types>
In dem generierten Code finden wir dies:
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.2-b05-
* Generated source version: 2.1
*
*/
@WebServiceClient(name = "YourService", targetNamespace = "http://test.webservice.services.xyz.com/", wsdlLocation = "/META-INF/wsdl/YourService.wsdl")
public class YourService_Service
extends Service
{
private final static URL YOURWEBSERVICE_WSDL_LOCATION;
private final static WebServiceException YOURWEBSERVICE_EXCEPTION;
private final static QName YOURWEBSERVICE_QNAME = new QName("http://test.webservice.services.xyz.com/", "YourService");
static {
YOURWEBSERVICE_WSDL_LOCATION = com.xyz.services.webservice.test.YourService_Service.class.getResource("/META-INF/wsdl/YourService.wsdl");
WebServiceException e = null;
if (YOURWEBSERVICE_WSDL_LOCATION == null) {
e = new WebServiceException("Cannot find '/META-INF/wsdl/YourService.wsdl' wsdl. Place the resource correctly in the classpath.");
}
YOURWEBSERVICE_EXCEPTION = e;
}
public YourService_Service() {
super(__getWsdlLocation(), YOURWEBSERVICE_QNAME);
}
public YourService_Service(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
/**
*
* @return
* returns YourService
*/
@WebEndpoint(name = "YourServicePort")
public YourService getYourServicePort() {
return super.getPort(new QName("http://test.webservice.services.xyz.com/", "YourServicePort"), YourService.class);
}
/**
*
* @param features
* A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values.
* @return
* returns YourService
*/
@WebEndpoint(name = "YourServicePort")
public YourService getYourServicePort(WebServiceFeature... features) {
return super.getPort(new QName("http://test.webservice.services.xyz.com/", "YourServicePort"), YourService.class, features);
}
private static URL __getWsdlLocation() {
if (YOURWEBSERVICE_EXCEPTION!= null) {
throw YOURWEBSERVICE_EXCEPTION;
}
return YOURWEBSERVICE_WSDL_LOCATION;
}
}
Vielleicht hilft das auch. Es ist nur ein anderer Ansatz, der nicht den "Katalog" Ansatz verwendet.
Ich hatte das exakte gleiche Problem, das hier beschrieben wird. Egal, was ich nach den oben genannten Beispielen tat, um den Speicherort meiner WSDL-Datei zu ändern (in unserem Fall von einem Webserver), sie verwies immer noch auf den ursprünglichen Speicherort, der in den Quellbaum des Serverprozesses eingebettet war.
Nachdem ich viele Stunden versucht hatte, dieses Problem zu beheben, stellte ich fest, dass die Exception immer in genau derselben Zeile (in meinem Fall 41) ausgelöst wurde. Heute Morgen beschloss ich schließlich, meinen Client-Quellcode an unseren Handelspartner zu schicken, damit er zumindest verstehen kann, wie der Code aussieht, aber vielleicht auch seinen eigenen erstellen kann. Zu meinem Schock und Entzücken fand ich in meinem Client-Quellcode einen Haufen Klassendateien, die mit meinen .java-Dateien vermischt waren. Wie bizarr!!! Ich vermute, dass diese ein Nebenprodukt des JAX-WS-Client-Builder-Tools waren.
Nachdem ich diese dummen .class-Dateien gelöscht und den Client-Code komplett bereinigt und neu erstellt hatte, funktionierte alles perfekt! Unglaublich!!
YMMV, Andrew