Klien JAX-WS: apa jalur yang benar untuk mengakses WSDL lokal?

86

Masalahnya adalah saya perlu membangun klien layanan web dari file yang telah saya sediakan. Saya telah menyimpan file ini di sistem file lokal dan, sementara saya menyimpan file WSDL di folder sistem file yang benar, semuanya baik-baik saja. Ketika saya menyebarkannya ke server atau menghapus WSDL dari folder sistem file, proxy tidak dapat menemukan WSDL dan memunculkan kesalahan. Saya telah mencari di web dan saya menemukan posting berikut ini, namun saya tidak dapat membuatnya berfungsi:
JAX-WS Memuat WSDL dari 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

Saya menggunakan NetBeans 6.1 (ini adalah aplikasi warisan yang telah saya perbarui dengan klien layanan web baru ini). Di bawah ini adalah kelas 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);
    }

}


Ini kode saya untuk menggunakan 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 meletakkan salinan WSDL di web-inf / wsdl / client / SOAService , jadi saya tidak ingin menambahkannya ke META-INF juga. Kelas layanan berada di WEB-INF / class / com / ibm / eci / soaservice / dan variabel baseurl berisi jalur lengkap sistem file ke sana (c: \ path \ to \ the \ project ... \ soaservice). Kode di atas menimbulkan kesalahan:

javax.xml.ws.WebServiceException: Gagal mengakses WSDL di: file: /WEB-INF/wsdl/client/SOAService.wsdl. Itu gagal dengan: \ WEB-INF \ wsdl \ client \ SOAService.wsdl (tidak dapat menemukan jalur)

Jadi, pertama-tama, haruskah saya memperbarui lokasi wsd dari kelas proxy? Lalu bagaimana cara mengetahui class SOAService di WEB-INF / class / com / ibm / eci / soaservice untuk mencari WSDL di \ WEB-INF \ wsdl \ client \ SOAService.wsdl?

DIEDIT : Saya telah menemukan tautan lain ini - http://jianmingli.com/wp/?cat=41 , yang mengatakan untuk meletakkan WSDL ke jalur kelas. Saya malu bertanya: bagaimana cara memasukkannya ke classpath aplikasi web?

ROMANIA_engineer
sumber
Pertanyaan serupa: JAX-WS Memuat WSDL dari jar
sleske

Jawaban:

117

Pilihan terbaik adalah menggunakan jax-ws-catalog.xml

Saat Anda mengkompilasi file WSDL lokal, timpa lokasi WSDL dan atur ke sesuatu seperti

http: //localhost/wsdl/SOAService.wsdl

Jangan khawatir ini hanya URI dan bukan URL, artinya Anda tidak harus memiliki WSDL yang tersedia di alamat itu.
Anda dapat melakukannya dengan meneruskan opsi wsdllocation ke kompiler wsdl ke java.

Melakukannya akan mengubah kode proxy Anda dari

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

untuk

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 pemberitahuan: // diubah menjadi http: // di konstruktor URL.

Sekarang hadir dalam jax-ws-catalog.xml. Tanpa jax-ws-catalog.xml jax-ws memang akan mencoba memuat WSDL dari lokasi

http: //localhost/wsdl/SOAService.wsdl
dan gagal, karena WSDL tersebut tidak akan tersedia.

Tetapi dengan jax-ws-catalog.xml Anda dapat mengarahkan jax-ws ke WSDL yang dikemas secara lokal setiap kali mencoba mengakses WSDL @

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

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

Apa yang Anda lakukan adalah memberi tahu jax-ws bahwa kapan pun WSDL perlu dimuat

http: //localhost/wsdl/SOAService.wsdl
, itu harus memuatnya dari jalur lokal wsdl / SOAService.wsdl.

Sekarang di mana Anda harus meletakkan wsdl / SOAService.wsdl dan jax-ws-catalog.xml? Itu pertanyaan jutaan dolar bukan?
Ini harus berada di direktori META-INF dari jar aplikasi Anda.

jadi seperti ini

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

Dengan cara ini Anda bahkan tidak perlu mengganti URL di klien Anda yang mengakses proxy. WSDL diambil dari dalam JAR Anda, dan Anda tidak perlu memiliki jalur sistem file yang di-hardcode dalam kode Anda.

Info lebih lanjut tentang jax-ws-catalog.xml http://jax-ws.java.net/nonav/2.1.2m1/docs/catalog-support.html

Semoga membantu


sumber
ok, saya tidak dapat memecahkan masalah dengan cara ini dalam aplikasi web: saya telah mencoba untuk meletakkan wsdl di dalam web-inf tidak berhasil, mungkin karena kurangnya pengetahuan saya. Bagaimanapun itu bekerja dengan toples, jadi saya akan membuat perpustakaan pembungkus, seperti yang seharusnya dilakukan dari awal. Terima kasih atas dukungan Anda
Saya dapat menggunakan jawaban ini dengan sukses dan saya percaya bahwa ini adalah solusi yang lebih baik daripada semua alternatif lain yang dokumen artikel dan tutorial lainnya. Jadi bagi saya ini adalah praktik terbaik. Saya hanya bertanya-tanya mengapa solusi ini tidak didokumentasikan di artikel dan tutorial resmi lainnya yang membahas topik JAX-WS.
Rahul Khimasia
19

Satu pendekatan lain yang telah berhasil kami lakukan adalah menghasilkan kode proxy klien WS menggunakan wsimport (dari Ant, sebagai tugas Ant) dan menentukan atribut wsdlLocation.

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

Karena kita menjalankan ini untuk sebuah proyek dengan beberapa WSDL, skrip menyelesaikan nilai $ (wsdl.file} secara dinamis yang diatur menjadi /META-INF/wsdl/YourWebServiceName.wsdl relatif terhadap lokasi JavaSource (atau / src, tergantung bagaimana Anda menyiapkan proyek). Selama proses pembuatan, file WSDL dan XSD disalin ke lokasi ini dan dikemas dalam file JAR. (mirip dengan solusi yang dijelaskan oleh Bhasakar di atas)

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

Catatan: pastikan file WSDL menggunakan referensi relatif ke XSD yang diimpor dan bukan 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>

Dalam kode yang dihasilkan , kami menemukan ini:

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

}

Mungkin ini bisa membantu juga. Ini hanya pendekatan berbeda yang tidak menggunakan pendekatan "katalog".

menandai
sumber
Saya suka pendekatan ini ... tetapi mengapa direktori META-INF?
IcedDante
1
Harap dicatat bahwa ini memerlukan penggunaan JAX-WS RI 2.2, bukan 2.1 yang disertakan dengan JDK 6 secara default
ᄂ ᄀ
4

Terima kasih banyak atas jawaban Bhaskar Karambelkar yang menjelaskan secara rinci dan memperbaiki masalah saya. Tetapi saya juga ingin menyampaikan kembali jawabannya dalam tiga langkah sederhana untuk seseorang yang sedang terburu-buru untuk memperbaikinya

  1. Jadikan referensi lokasi lokal wsdl Anda sebagai wsdlLocation= "http://localhost/wsdl/yourwsdlname.wsdl"
  2. Buat folder META-INF tepat di bawah src. Letakkan file wsdl Anda dalam folder di bawah META-INF, katakan META-INF / wsdl
  3. Buat file xml jax-ws-catalog.xml di bawah META-INF seperti di bawah ini

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

Sekarang kemas toples Anda. Tidak ada lagi referensi ke direktori lokal, semuanya dikemas dan direferensikan di dalamnya

Hemus7
sumber
4

Bagi mereka yang masih mencari solusi di sini, solusi termudah adalah menggunakan <wsdlLocation>, tanpa mengubah kode apa pun. Langkah kerja diberikan di bawah ini:

  1. Letakkan wsdl Anda ke direktori sumber daya seperti: src/main/resource
  2. Di file pom, tambahkan wsdlDirectory dan wsdlLocation (jangan lewatkan / di awal wsdlLocation), seperti di bawah ini. Sementara wsdlDirectory digunakan untuk menghasilkan kode dan wsdlLocation digunakan saat runtime untuk membuat proxy dinamis.

    <wsdlDirectory>src/main/resources/mydir</wsdlDirectory>
    <wsdlLocation>/mydir/my.wsdl</wsdlLocation>
    
  3. Kemudian di kode java Anda (dengan konstruktor no-arg):

    MyPort myPort = new MyPortService().getMyPort();
    
  4. Untuk kelengkapan, saya menyediakan di sini bagian pembuatan kode lengkap, dengan api yang lancar dalam kode yang dihasilkan.

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

Shafiul
sumber
0

Memiliki masalah yang sama persis dengan yang dijelaskan di sini. Tidak peduli apa yang saya lakukan, mengikuti contoh di atas, untuk mengubah lokasi file WSDL saya (dalam kasus kami dari server web), itu masih merujuk ke lokasi asli yang tertanam dalam pohon sumber proses server.

Setelah BANYAK jam mencoba men-debug ini, saya perhatikan bahwa Pengecualian selalu dilemparkan dari baris yang sama persis (dalam kasus saya 41). Akhirnya pagi ini, saya memutuskan untuk mengirim kode klien sumber saya ke mitra dagang kami sehingga mereka setidaknya dapat memahami bagaimana kodenya terlihat, tetapi mungkin membuatnya sendiri. Yang membuat saya terkejut dan ngeri, saya menemukan banyak file kelas bercampur dengan file .java saya dalam pohon sumber klien saya. Aneh sekali !! Saya menduga ini adalah produk sampingan dari alat pembuat klien JAX-WS.

Setelah saya menghapus file .class konyol itu dan melakukan pembersihan dan rekondisi kode klien sepenuhnya, semuanya bekerja dengan sempurna !! Tidak masuk akal !!

YMMV, Andrew

Piko
sumber