1

我目前正在一个项目中工作,我们希望使用 Maven 的 jaxws-maven-plugin 自动生成 Web 服务客户端。目前,Web 服务客户端是使用用于 Web 服务客户端生成的 IBM RAD 8.0 内部工具生成的。

这很好用,但是随着 Web 服务数量的增加,这个过程变得太慢了。虽然我们可以让 Maven 插件在客户端项目中生成 Java 类并在本地服务器的本地开发中使用它们,但当我们尝试部署它时,Web 服务的验证失败。这是由于服务器基础设施,当测试在每台服务器上成功运行时,项目需要逐步通过测试、阶段和生产服务器,并进一步部署。

部署后,Websphere Portal Servr 尝试根据包中生成的绑定 Java 文件中给出的 WSDL 定义来验证生成的 Web 服务客户端。运行 maven 插件时,会产生以下绑定:

我的项目HttpService

 static {
    URL url = null;
    WebServiceException e = null;
    try {
        url = new URL("http://localhost:9080/MyProjectWeb/sca/MyProjectExportWS?wsdl");
    } catch (MalformedURLException ex) {
        e = new WebServiceException(ex);
    }

因为生成的 Web 项目需要从同一个 EAR 文件在每台服务器上运行,所以我们无法在服务器之间更改 WSDL 文件中的 URL。

RAD 的导入工具会生成一个绑定文件,该文件使用类加载器来获取文件:

我的项目HttpService

static {
    URL url = null;
    try {
        url = com.my.package.portal.MyProjectHttpService.class.getResource("/WEB-INF/wsdl/project/interfaces/MyProjectExport1.wsdl");
        if (url == null) throw new MalformedURLException("/WEB-INF/wsdl/project/interfaces/MyProjectExport1.wsdl does not exist in the module.");
    } catch (MalformedURLException e) {
       ...
    }

In order to find a solution we went as far as writing our own Maven plugin that downloads the XSD and WSDL files and puts them in the build package, so they could be used to generate the web service client with the wsimport plugin afterwards, but using instead of . However, this was not successull as well, as the binding file would be produced with an absolute path:

 static {
    URL url = null;
    WebServiceException e = null;
    try {
        url = new URL("file:/D:/mavenworkspace/testproject/target/META-INF/wsdl/com/my/package/portal/ws/interfaces/MyProjectExport1.wsdl");
    } catch (MalformedURLException ex) {
        e = new WebServiceException(ex);
    }
  }

Any help on how we can resolve the problem would be welcome. We don't really care on how we can achieve the result of having all of the XSD and WSDL file inside our jar, being referenced relatively, so the environment doesn't matter when the webserver tries to validate the web service client.

PS: Sadly, we also cannot use multiple profiles for the different environments.

4

1 回答 1

0

After some trying I was finally able to resolve our problem. We came onto the right track by this blogpost (and the ones linked in it): http://blog.vinodsingh.com/2008/12/locally-packaged-wsdl.html

We ended up with a custom solution which combines a new maven plugin and usage of the wsimport plugin. Our own plugin does some preliminary work by downloading all .wsdl and .xsd files for a given URL. I am not allowed to share the code, but I want to give some hints on how our plugin works, so that anybody in the same situation as us can hack a fitting plugin ;)

This is the build part of the pom file of the project that becomes our web service client:

<build>
    <plugins>
        <plugin>
            <groupId>com.my.company</groupId>
            <artifactId>wsdl-import</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <executions>
                <execution>
                    <goals>
                        <goal>wsdlimport</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <wsdlUrls>
                    <wsdlUrl>http://serveraddress/MYWEBSERVICEMODULE/WEBSERVICe?wsdl</wsdlUrl>
                </wsdlUrls>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.jvnet.jax-ws-commons</groupId>
            <artifactId>jaxws-maven-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <target>2.1</target>
                <keep>true</keep>
            </configuration>
            <executions>
                <execution>
                    <phase>generate-sources</phase>
                    <goals>
                        <goal>wsimport</goal>
                    </goals>
                    <configuration>
                        <wsdlLocation>/wsdl/com/my/company/WEBSERVICEEXPORT.wsdl</wsdlLocation>
                        <wsdlUrls>
                            <wsdlUrl>${project.build.directory}/META-INF/wsdl/com/my/company/WEBSERVICEEXPORT.wsdl</wsdlUrl>
                        </wsdlUrls>
                    </configuration>
                </execution
            </executions>   
        </plugin>
    </plugins>
    <resources>
        <resource>
            <directory>${project.build.directory}/META-INF/</directory>
        </resource>
    </resources>
</build>

Our plugin wsdlimport is build similar to the wsimport plugin. It takes a set of WSDL files in the tag. Each wsdl file is downloaded and the resulting document parsed using XPath. For each XML node that is either an "xsd:import" or "xsd:include" element, the path of the schema location is extracted and the parsed for further nodes that include (other) XSD files. What you need to look out for are nodes that reference other elements that are not simple types:

<xsd:element maxOccurs="unbounded" minOccurs="0" name="persons" type="bons1:BOPerson">
<xsd:element maxOccurs="unbounded" minOccurs="0" name="names" type="xsd:string">

Such elements have another namespace than simple types, which are in the xsd namespace. In our case, we have custom namespaces bons1 and bons2 (I guess BO-Namespace 1 and 2) for our BOs.

The plugin is configured to place all wsdl files in the target directory in a folder "META-INF/wsdl/packagepath/"

After that, the normal wsimport plugin takes over: We define to point to the path "/wsdl/packagepath/" (like above, but without the META-INF). As wsdlUrl we supply the local path to the downloaded WSDL file. This generates our java implementation.

Finally, for the downloaded and generated files to work, you need to define the META-INF folder as a resource so it is bundled into the output .jar file. By defining the META-INF folder, the WSDL and XSD files will be packaged with "/wsdl" being in the root directory of the .jar. That's why we defined the to be "/wsdl/packagepath/..." instead of "/META-INF/wsdl/packagepath/...".

I hope this helps to solve similar problems in the future.

于 2013-01-31T12:22:25.843 回答