web-dev-qa-db-fra.com

Client JAX-WS: quel est le chemin correct pour accéder au WSDL local?

Le problème est que je dois créer un client de service Web à partir d'un fichier qui m'a été fourni. J'ai stocké ce fichier sur le système de fichiers local et, même si je conserve le fichier WSDL dans le dossier du système de fichiers approprié, tout va bien. Lorsque je le déploie sur un serveur ou que je supprime le WSDL du dossier du système de fichiers, le proxy ne peut pas trouver le WSDL et génère une erreur. J'ai effectué des recherches sur le Web et j'ai trouvé les articles suivants, mais je n'ai pas réussi à le faire fonctionner:
JAX-WS Chargement de WSDL à partir du fichier jar
http://www.Java.net/forum/topic/glassfish/metro-and-jaxb/client-jar-cant-find-local-wsdl-
http://blog.vinodsingh.com/2008/12/locally-packaged-wsdl.html

J'utilise NetBeans 6.1 (c'est une application héritée que je dois mettre à jour avec ce nouveau client de service Web). Vous trouverez ci-dessous la classe de 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);
    }

}


Ceci est mon code pour utiliser le 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 a mis une copie du WSDL dans web-inf/wsdl/client/SOAService, je ne souhaite donc pas l'ajouter à META-INF . Les classes de service sont dans WEB-INF/classes/com/ibm/eci/soaservice / et la variable baseurl contient le chemin complet du système de fichiers (c:\chemin\vers\le\projet .. .\soaservice). Le code ci-dessus soulève l'erreur:

javax.xml.ws.WebServiceException: impossible d'accéder au WSDL à: fichier: /WEB-INF/wsdl/client/SOAService.wsdl. Il a échoué avec:\WEB-INF\wsdl\client\SOAService.wsdl (le chemin ne peut pas être trouvé)

Donc, tout d’abord, dois-je mettre à jour la wsdllocation de la classe proxy? Alors, comment indiquer à la classe SOAService dans WEB-INF/classes/com/ibm/eci/soaservice de rechercher le fichier WSDL dans\WEB-INF\wsdl\client\SOAService.wsdl?

[~ # ~] édité [~ # ~] : J'ai trouvé cet autre lien - http://jianmingli.com/ wp /? cat = 41 , qui dit de mettre le WSDL dans le classpath. J'ai honte de demander: comment puis-je le mettre dans le classpath d'une application Web?

81
user260192

La meilleure option consiste à utiliser jax-ws-catalog.xml

Lorsque vous compilez le fichier WSDL local, remplacez l’emplacement WSDL et définissez-le comme suit.

 http: //localhost/wsdl/SOAService.wsdl 

Ne vous inquiétez pas, il s'agit uniquement d'un URI et non d'une URL, ce qui signifie que vous n'avez pas besoin d'avoir le WSDL disponible à cette adresse.
Vous pouvez le faire en transmettant l’option wsdllocation au wsdl à Java compilateur.

Cela changera votre code proxy de

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

à

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

Notice file: // a été modifiée en http: // dans le constructeur de l'URL.

Maintenant, vient dans jax-ws-catalog.xml. Sans jax-ws-catalog.xml, jax-ws tentera en effet de charger le WSDL à partir de l'emplacement

http: //localhost/wsdl/SOAService.wsdl

Mais avec jax-ws-catalog.xml, vous pouvez rediriger jax-ws vers un WSDL empaqueté localement chaque fois qu’il tente d’accéder au WSDL @

http: //localhost/wsdl/SOAService.wsdl

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

Ce que vous faites est de dire à jax-ws que chaque fois qu’il faut charger WSDL depuis

http: //localhost/wsdl/SOAService.wsdl

Maintenant, où devriez-vous mettre wsdl/SOAService.wsdl et jax-ws-catalog.xml? C'est la question à un million de dollars, n'est-ce pas?
Il doit figurer dans le répertoire META-INF de votre fichier JAR d’application.

donc quelque chose comme ça

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

De cette façon, vous n'avez même pas à remplacer l'URL de votre client qui accède au proxy. Le WSDL est extrait de votre fichier JAR et vous évitez d'avoir des chemins de système de fichiers codés en dur dans votre code.

Plus d'infos sur jax-ws-catalog.xml http://jax-ws.Java.net/nonav/2.1.2m1/docs/catalog-support.html

J'espère que ça t'as aidé

111
user507484

Une autre approche que nous avons adoptée consiste à générer le code proxy du client WS à l'aide de wsimport (à partir de Ant, en tant que tâche Ant) et à spécifier l'attribut wsdlLocation.

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

Puisque nous exécutons ceci pour un projet avec plusieurs WSDL, le script résout la valeur $ (wsdl.file}) définie de manière dynamique pour être /META-INF/wsdl/YourWebServiceName.wsdl par rapport à l'emplacement de JavaSource (ou/src, Selon la configuration de votre projet) Au cours du processus de construction, les fichiers WSDL et XSD sont copiés à cet emplacement et intégrés dans le fichier JAR (similaire à la solution décrite par Bhasakar ci-dessus).

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

Remarque: assurez-vous que les fichiers WSDL utilisent des références relatives à des fichiers XSD importés et non à des 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>

Dans le code généré, on trouve ceci:

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

}

Peut-être que cela pourrait aider aussi. C'est juste une approche différente qui n'utilise pas l'approche "catalogue".

17
mark

Merci beaucoup pour la réponse de Bhaskar Karambelkar qui explique en détail et corrige mon problème. Mais je voudrais aussi reformuler la réponse en trois étapes simples pour quelqu'un qui est pressé de réparer

  1. Définissez votre référence d’emplacement local wsdl sous la forme wsdlLocation= "http://localhost/wsdl/yourwsdlname.wsdl"
  2. Créez un dossier META-INF juste sous le src. Placez votre/vos fichier (s) wsdl dans un dossier sous META-INF, dites META-INF/wsdl.
  3. Créez un fichier xml jax-ws-catalog.xml sous META-INF comme ci-dessous

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

Maintenant, emballez votre pot. Plus de référence au répertoire local, tout est emballé et référencé dans

4
Hemus7

Pour ceux d'entre vous qui utilisent Spring, vous pouvez simplement référencer n'importe quelle ressource classpath à l'aide du protocole classpath. Donc, dans le cas de wsdlLocation, cela devient:

<wsdlLocation>classpath:META-INF/webservice.wsdl</wsdlLocation>

Notez que ce n'est pas un comportement standard Java. Voir aussi: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/resources. html

1
Martin Devillers

Avait le exact même problème qui est décrit ici. Peu importe ce que j'ai fait, en suivant les exemples ci-dessus, pour changer l'emplacement de mon fichier WSDL (dans notre cas, à partir d'un serveur Web), il faisait toujours référence à l'emplacement d'origine intégré dans l'arborescence source du processus du serveur.

Après PLUSIEURS heures à essayer de résoudre ce problème, j'ai remarqué que l'exception était toujours renvoyée de la même ligne (dans mon cas, 41). Enfin, ce matin, j'ai décidé d'envoyer mon code client source à notre partenaire commercial afin qu'il puisse au moins comprendre à quoi ressemble le code, mais peut-être créer le sien. Pour mon choc et horreur, j'ai trouvé un tas de fichiers de classe mélangés à mes fichiers .Java dans l'arborescence source de mon client. Comme c'est bizarre !! Je soupçonne qu’il s’agit d’un sous-produit de l’outil de création de client JAX-WS.

Une fois que j'ai zappé ces stupides fichiers .class et effectué un nettoyage complet et une reconstruction du code client, tout fonctionne parfaitement! Redonculous !!

YMMV, Andrew

0
Piko