Клиент JAX-WS: какой правильный путь для доступа к локальному WSDL? - PullRequest
81 голосов
/ 12 ноября 2010

Проблема в том, что мне нужно собрать клиент веб-сервиса из предоставленного мне файла. Я сохранил этот файл в локальной файловой системе и, хотя я храню файл WSDL в правильной папке файловой системы, все в порядке. Когда я развертываю его на сервере или удаляю WSDL из папки файловой системы, прокси не может найти WSDL и выдает ошибку. Я искал в Интернете и нашел следующие сообщения, но не смог заставить его работать:
JAX-WS Загрузка WSDL из банки
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

Я использую NetBeans 6.1 (это устаревшее приложение, которое я должен обновить с помощью этого нового клиента веб-службы). Ниже представлен прокси-класс 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);
    }

}


Это мой код для использования прокси:

   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 помещает копию WSDL в web-inf / wsdl / client / SOAService , поэтому я не хочу добавлять ее также в META-INF . Классы обслуживания находятся в WEB-INF / classes / com / ibm / eci / soaservice / , а переменная baseurl содержит полный путь к файловой системе (c: \ path \ to \ the \ project ... \ soaservice ). Приведенный выше код вызывает ошибку:

javax.xml.ws.WebServiceException: Не удалось получить доступ к WSDL по адресу: file: /WEB-INF/wsdl/client/SOAService.wsdl. Это не удалось с: \ WEB-INF \ wsdl \ client \ SOAService.wsdl (не удается найти путь)

Итак, прежде всего, я должен обновить wsdllocation класса прокси? Тогда как мне указать классу SOAService в WEB-INF / classes / com / ibm / eci / soaservice искать WSDL в \ WEB-INF \ wsdl \ client \ SOAService.wsdl?

РЕДАКТИРОВАНИЕ : я нашел другую ссылку - http://jianmingli.com/wp/?cat=41,, в которой говорится, что WSDL должен быть помещен в путь к классам. Мне стыдно спрашивать: как мне поместить его в classpath веб-приложения?

Ответы [ 5 ]

111 голосов
/ 14 ноября 2010

Лучшим вариантом является использование jax-ws-catalog.xml

Когда вы компилируете локальный файл WSDL, переопределяете местоположение WSDL и задаете для него что-то вроде

http://localhost/wsdl/SOAService.wsdl

Donне беспокойтесь, это всего лишь URI, а не URL, то есть вам не нужно иметь WSDL по этому адресу.
Вы можете сделать это, передав параметр wsdllocation в wsdl компилятору java.

Это изменит ваш прокси-код с

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

Файл уведомления: // в конструкторе URL изменен на http: //.

Теперь входит в jax-ws-catalog.xml.Без jax-ws-catalog.xml jax-ws действительно попытается загрузить WSDL из местоположения

<a href="http://localhost/wsdl/SOAService.wsdl" rel="noreferrer">http://localhost/wsdl/SOAService.wsdl</a>
и завершится неудачей, поскольку такой WSDL не будет доступен.

Но с jax-ws-catalog.xmlвы можете перенаправить jax-ws в локально упакованный WSDL всякий раз, когда он пытается получить доступ к WSDL @

<a href="http://localhost/wsdl/SOAService.wsdl" rel="noreferrer">http://localhost/wsdl/SOAService.wsdl</a>
.

Вот 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>

Что вы делаетесообщает jax-ws, что когда ему необходимо загрузить WSDL из

<a href="http://localhost/wsdl/SOAService.wsdl" rel="noreferrer">http://localhost/wsdl/SOAService.wsdl</a>
, он должен загрузить его по локальному пути wsdl / SOAService.wsdl.

Теперь куда следует поместить wsdl / SOAService.wsdl и jax-ws-catalog.xml?Это вопрос на миллион долларов, не так ли?
Он должен быть в каталоге META-INF вашего приложения jar.

так что-то вроде этого

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

Таким образом, вам даже не придется переопределять URL в вашем клиенте, который обращается к прокси.WSDL выбирается из вашего JAR-файла, и вам не нужно иметь жестко запрограммированные пути файловой системы в вашем коде.

Дополнительная информация о jax-ws-catalog.xml http://jax -ws.java.net/nonav/2.1.2m1/docs/catalog-support.html

Надеюсь, что поможет

17 голосов
/ 29 ноября 2010

Еще один подход, который мы успешно применили, - это сгенерировать прокси-код клиента WS с использованием wsimport (из Ant в качестве задачи Ant) и указать атрибут wsdlLocation.

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

Поскольку мы запускаем это для проекта с несколькими WSDL, сценарий динамически разрешает значение $ (wsdl.file}, которое настроено на /META-INF/wsdl/YourWebServiceName.wsdl относительно расположения JavaSource (или / src, в зависимости от того, как настроен ваш проект.) Во время сборки файлы WSDL и XSDs копируются в это место и упаковываются в файл JAR (аналогично решению, описанному выше Bhasakar)

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

Примечание: убедитесь, что файлы WSDL используют относительные ссылки на любые импортированные XSD, а не http-URL:

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

В сгенерированном коде мы находим это:

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

}

Возможно, это тоже может помочь. Это просто другой подход, который не использует подход «каталога».

4 голосов
/ 31 декабря 2015

Спасибо большое за ответ Бхаскара Карамбелкара, который подробно объясняет и исправляет мою проблему.Но я также хотел бы перефразировать ответ в три простых шага для тех, кто спешит исправить

  1. Сделайте ссылку на локальное местоположение wsdl как wsdlLocation= "http://localhost/wsdl/yourwsdlname.wsdl"
  2. СоздайтеПапка META-INF прямо под src.Поместите файл / файлы wsdl в папку в META-INF, скажем, META-INF / wsdl
  3. Создайте XML-файл jax-ws-catalog.xml в META-INF, как показано ниже

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

Теперь упакуйте свою банку.Больше нет ссылки на локальный каталог, все упаковано и на него ссылаются в

1 голос
/ 07 декабря 2016

Для тех из вас, кто использует Spring, вы можете просто ссылаться на любой classpath-ресурс, используя classpath-протокол.Так что в случае wsdlLocation это становится:

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

Обратите внимание, что это не стандартное поведение JavaСмотрите также: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/resources.html

0 голосов
/ 08 февраля 2012

Была точная та же проблема, которая описана здесь.Независимо от того, что я сделал, следуя приведенным выше примерам, чтобы изменить расположение моего файла WSDL (в нашем случае с веб-сервера), он все равно ссылался на исходное расположение, встроенное в дерево исходных текстов серверного процесса.1004 * После МНОГО часов попыток отладить это, я заметил, что Исключение всегда выдается из одной и той же строки (в моем случае 41).Наконец этим утром я решил просто отправить свой исходный код клиента нашему торговому партнеру, чтобы он мог хотя бы понять, как выглядит код, но, возможно, создать свой собственный.К моим shock и horror я обнаружил несколько файлов классов, смешанных с моими файлами .java в моем исходном дереве клиента.Как странно!Я подозреваю, что это был побочный продукт инструмента построения клиента JAX-WS.

Как только я зарезал эти глупые файлы .class и выполнил полную очистку и перестройку клиентского кода, все работает отлично !!Redonculous !!

YMMV, Андрей

...