Клиент JAX-WS: каков правильный путь для доступа к локальному WSDL?



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



Я использую 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;

//classescomibmecisoaservice
//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:pathtotheproject...soaservice). Приведенный выше код вызывает ошибку:




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




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



редактировать: я нашел эту другую ссылку -http://jianmingli.com/wp/?cat=41, которые говорят, чтобы поместить WSDL в путь к классам. Мне стыдно спрашивать: как поместить его в путь к классу веб-приложения?

1788   5  

5 ответов:

лучший вариант-использовать JAX-ws-catalog.xml

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

http://localhost/wsdl/SOAService.wsdl

Не волнуйтесь, это только URI , а не URL, то есть вам не нужно иметь WSDL, доступный по этому адресу.
Это можно сделать, передав параметр wsdllocation компилятору WSDL to 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;
}

to

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

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

теперь поставляется в JAX-ws-catalog.XML. Без JAX-ws-каталога.XML-код в JAX-WS в самом деле будет пытаться загрузить WSDL-файл из папки

http://localhost/wsdl/SOAService.wsdl
и потерпеть неудачу, так как такой WSDL не будет доступен.

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

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

вот JAX-ws-каталог.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 из

http://localhost/wsdl/SOAService.wsdl
, он должен загрузить его из локального пути wsdl / SOAService.язык WSDL.

теперь, где вы должны поместить wsdl / SOAService.wsdl и JAX-WS-каталог.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

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

еще один подход, который мы успешно приняли, заключается в создании прокси-кода клиента 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.файл} значение динамически, которое устанавливается как /META-INF/wsdl/YourWebServiceName.wsdl относительно расположения JavaSource (или /src, в зависимости от того, как вы настроили свой проект). Во время процесса сборки, файлы WSDL и XSDs копируются в это расположение и упаковываются в файл JAR. (аналогично решению, описанному Бхасакаром выше)

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

Примечание: убедитесь, что файлы WSDL используют относительные ссылки на любые импортированные XSDs, а не 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;
    }

}

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

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

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

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

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

для тех из вас, кто использует 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

имел точно та же проблема, что описана здесь. Независимо от того, что я сделал, следуя приведенным выше примерам, чтобы изменить местоположение моего файла WSDL (в нашем случае с веб-сервера), он все еще ссылался на исходное местоположение, встроенное в исходное дерево серверного процесса.

после много часы, пытаясь отладить это, я заметил, что исключение всегда выбрасывается из одной и той же строки (в моем случае 41). Наконец сегодня утром, я решил просто отправить мой исходный код клиента нашему торговому партнеру, чтобы они могли хотя бы понять, как выглядит код, но, возможно, построить свой собственный. К моему шок и ужасы Я нашел кучу файлов классов, смешанных с моими .java-файлы в исходном дереве моего клиента. Как странно!! Я подозреваю, что это был побочный продукт инструмента JAX-WS client builder.

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

YMMV, Андрей

Comments

    Ничего не найдено.