Client JAX-WS: qual è il percorso corretto per accedere al WSDL locale?


86

Il problema è che devo creare un client di servizi Web da un file che mi è stato fornito. Ho memorizzato questo file sul file system locale e, mentre tengo il file WSDL nella cartella del file system corretta, va tutto bene. Quando lo distribuisco su un server o rimuovo il WSDL dalla cartella del file system, il proxy non riesce a trovare il WSDL e genera un errore. Ho cercato sul web e ho trovato i seguenti post ma non sono riuscito a farlo funzionare:
JAX-WS Caricamento WSDL da jar
http://www.java.net/forum/topic/glassfish/metro -e-jaxb / client-jar-cant-find-local-wsdl-0
http://blog.vinodsingh.com/2008/12/locally-packaged-wsdl.html

Sto usando NetBeans 6.1 (questa è un'applicazione legacy che devo aggiornare con questo nuovo client di servizi web). Di seguito è riportata la classe proxy JAX-WS:

    @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);
    }

}


Questo è il mio codice per utilizzare il proxy:

   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 ha messo una copia del WSDL in web-inf / wsdl / client / SOAService , quindi non voglio aggiungerlo anche a META-INF . Le classi di servizio si trovano in WEB-INF / classes / com / ibm / eci / soaservice / e la variabile baseurl contiene il percorso completo del file system (c: \ path \ to \ the \ project ... \ soaservice). Il codice precedente genera l'errore:

javax.xml.ws.WebServiceException: impossibile accedere a WSDL in: file: /WEB-INF/wsdl/client/SOAService.wsdl. Non è riuscito con: \ WEB-INF \ wsdl \ client \ SOAService.wsdl (impossibile trovare il percorso)

Quindi, prima di tutto, devo aggiornare la wsdllocation della classe proxy? Allora come faccio a dire alla classe SOAService in WEB-INF / classes / com / ibm / eci / soaservice di cercare WSDL in \ WEB-INF \ wsdl \ client \ SOAService.wsdl?

MODIFICATO : ho trovato questo altro collegamento - http://jianmingli.com/wp/?cat=41 , che dice di mettere il WSDL nel classpath. Mi vergogno a chiedere: come lo inserisco nel classpath dell'applicazione web?


Risposte:


117

L'opzione migliore è usare jax-ws-catalog.xml

Quando compili il file WSDL locale, sovrascrivi il percorso WSDL e impostalo su qualcosa di simile

http: //localhost/wsdl/SOAService.wsdl

Non preoccuparti, questo è solo un URI e non un URL, il che significa che non devi avere il WSDL disponibile a quell'indirizzo.
Puoi farlo passando l'opzione wsdllocation al compilatore wsdl to java.

In questo modo cambierai il tuo codice proxy da

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;
}

per

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;
}

File di avviso: // modificato in http: // nel costruttore dell'URL.

Ora è disponibile in jax-ws-catalog.xml. Senza jax-ws-catalog.xml jax-ws proverà effettivamente a caricare il WSDL dalla posizione

http: //localhost/wsdl/SOAService.wsdl
e fallire, poiché nessun WSDL di questo tipo sarà disponibile.

Ma con jax-ws-catalog.xml puoi reindirizzare jax-ws a un WSDL pacchettizzato localmente ogni volta che tenta di accedere a WSDL @

http: //localhost/wsdl/SOAService.wsdl
.

Ecco 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>

Quello che stai facendo è dire a jax-ws che quando mai è necessario caricare WSDL da

http: //localhost/wsdl/SOAService.wsdl
, dovrebbe caricarlo dal percorso locale wsdl / SOAService.wsdl.

Ora dove dovresti mettere wsdl / SOAService.wsdl e jax-ws-catalog.xml? Questa è la domanda da un milione di dollari, non è vero?
Dovrebbe essere nella directory META-INF del jar dell'applicazione.

quindi qualcosa del genere

ABCD.jar  
| __ META-INF    
    | __ jax-ws-catalog.xml  
    | __ wsdl  
        | __ SOAService.wsdl  

In questo modo non devi nemmeno sovrascrivere l'URL nel tuo client che accede al proxy. Il WSDL viene prelevato dall'interno del tuo JAR ed eviti di dover avere percorsi del filesystem hard-coded nel tuo codice.

Maggiori informazioni su jax-ws-catalog.xml http://jax-ws.java.net/nonav/2.1.2m1/docs/catalog-support.html

Spero possa aiutare


ok, non sono riuscito a risolvere il problema in questo modo all'interno dell'applicazione web: ho provato a mettere wsdl all'interno di web-inf senza successo, probabilmente per la mia scarsa conoscenza. Comunque funziona con un jar, quindi creerò una libreria wrapper, come avrebbe dovuto essere fatto dall'inizio. Grazie per il vostro supporto

Sono stato in grado di utilizzare questa risposta con successo e credo che questa sia una soluzione migliore di tutte le altre alternative documentate da altri articoli e tutorial. Quindi per me questa è la migliore pratica. Mi chiedo solo perché questa soluzione non sia documentata negli altri articoli e tutorial ufficiali che trattano l'argomento JAX-WS.
Rahul Khimasia

19

Un altro approccio che abbiamo adottato con successo è generare il codice proxy del client WS utilizzando wsimport (da Ant, come attività Ant) e specificare l'attributo wsdlLocation.

<wsimport debug="true" keep="true" verbose="false" target="2.1" sourcedestdir="${generated.client}" wsdl="${src}${wsdl.file}" wsdlLocation="${wsdl.file}">
</wsimport>

Poiché lo eseguiamo per un progetto con più WSDL, lo script risolve dinamicamente il valore $ (wsdl.file} che è impostato per essere /META-INF/wsdl/YourWebServiceName.wsdl relativo al percorso JavaSource (o / src, a seconda di come hai configurato il tuo progetto). Durante il processo di compilazione, i file WSDL e XSD vengono copiati in questa posizione e impacchettati nel file JAR. (simile alla soluzione descritta da Bhasakar sopra)

MyApp.jar
|__META-INF
   |__wsdl
      |__YourWebServiceName.wsdl
      |__YourWebServiceName_schema1.xsd
      |__YourWebServiceName_schmea2.xsd

Nota: assicurati che i file WSDL utilizzino i riferimenti relativi a qualsiasi XSD importato e non URL http:

  <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>

Nel codice generato troviamo questo:

/**
 * 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;
    }

}

Forse anche questo potrebbe aiutare. È solo un approccio diverso che non utilizza l'approccio "catalogo".


Mi piace questo approccio ... ma perché la directory META-INF?
IcedDante

1
Si prega di notare che questo richiede l'uso di JAX-WS RI 2.2, non 2.1 che viene fornito con JDK 6 per impostazione predefinita
ᄂ ᄀ

4

Grazie mille per la risposta di Bhaskar Karambelkar che spiega in dettaglio e ha risolto il mio problema. Ma vorrei anche riformulare la risposta in tre semplici passaggi per qualcuno che ha fretta di aggiustarla

  1. Rendi il tuo riferimento alla posizione locale wsdl come wsdlLocation= "http://localhost/wsdl/yourwsdlname.wsdl"
  2. Crea una cartella META-INF proprio sotto il file src. Metti i tuoi file wsdl in una cartella sotto META-INF, ad esempio META-INF / wsdl
  3. Crea un file xml jax-ws-catalog.xml in META-INF come sotto

    <catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system"> <system systemId="http://localhost/wsdl/yourwsdlname.wsdl" uri="wsdl/yourwsdlname.wsdl" /> </catalog>

Ora impacchetta il tuo barattolo. Niente più riferimento alla directory locale, è tutto impacchettato e referenziato all'interno


4

Per coloro che stanno ancora cercando una soluzione qui, la soluzione più semplice sarebbe quella di utilizzare <wsdlLocation>, senza modificare alcun codice. Di seguito sono riportate le fasi di lavoro:

  1. Metti il ​​tuo wsdl nella directory delle risorse come: src/main/resource
  2. Nel file pom, aggiungi sia wsdlDirectory che wsdlLocation (da non perdere / all'inizio di wsdlLocation), come di seguito. Mentre wsdlDirectory viene utilizzato per generare codice e wsdlLocation viene utilizzato in fase di esecuzione per creare proxy dinamico.

    <wsdlDirectory>src/main/resources/mydir</wsdlDirectory>
    <wsdlLocation>/mydir/my.wsdl</wsdlLocation>
    
  3. Quindi nel tuo codice java (con il costruttore no-arg):

    MyPort myPort = new MyPortService().getMyPort();
    
  4. Per completezza, sto fornendo qui la parte completa della generazione del codice, con API fluente nel codice generato.

    <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxws-maven-plugin</artifactId>
    <version>2.5</version>
    
    <dependencies>
        <dependency>
            <groupId>org.jvnet.jaxb2_commons</groupId>
            <artifactId>jaxb2-fluent-api</artifactId>
            <version>3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.ws</groupId>
            <artifactId>jaxws-tools</artifactId>
            <version>2.3.0</version>
        </dependency>
    </dependencies>
    
    <executions>
        <execution>
            <id>wsdl-to-java-generator</id>
            <goals>
                <goal>wsimport</goal>
            </goals>
            <configuration>
                <xjcArgs>
                    <xjcArg>-Xfluent-api</xjcArg>
                </xjcArgs>
                <keep>true</keep>
                <wsdlDirectory>src/main/resources/package</wsdlDirectory>
                <wsdlLocation>/package/my.wsdl</wsdlLocation>
                <sourceDestDir>${project.build.directory}/generated-sources/annotations/jaxb</sourceDestDir>
                <packageName>full.package.here</packageName>
            </configuration>
        </execution>
    </executions>
    



0

Aveva l' esatto stesso problema descritto qui. Indipendentemente da ciò che ho fatto, seguendo gli esempi precedenti, per modificare la posizione del mio file WSDL (nel nostro caso da un server Web), faceva ancora riferimento alla posizione originale incorporata nell'albero dei sorgenti del processo del server.

Dopo MOLTE ore cercando di eseguire il debug di questo, ho notato che l'eccezione veniva sempre lanciata dalla stessa identica riga (nel mio caso 41). Finalmente questa mattina, ho deciso di inviare il mio codice cliente sorgente al nostro partner commerciale in modo che possano almeno capire come appare il codice, ma forse costruirne uno proprio. Con mio grande shock e orrore ho trovato un mucchio di file di classe mescolati con i miei file .java all'interno del mio albero dei sorgenti del client. Che bizzarro !! Sospetto che si tratti di un sottoprodotto dello strumento di creazione del client JAX-WS.

Una volta che ho eliminato quegli stupidi file .class e ho eseguito una pulizia completa e una ricostruzione del codice client, tutto funziona perfettamente !! Ridoncello !!

YMMV, Andrew

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.