For public web services, the WSDL file will typically be available on the web site of the organization that publishes the web service. For private web services, contact the organization that supports the web service to obtain the WSDL file. WSDL files can also be found through both public and private UDDI registries.
The best option is to use jax-ws-catalog.xml
When you compile the local WSDL file , override the WSDL location and set it to something like
http://localhost/wsdl/SOAService.wsdl
Don't worry this is only a URI and not a URL , meaning you don't have to have the WSDL available at that address.
You can do this by passing the wsdllocation option to the wsdl to java compiler.
Doing so will change your proxy code from
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;
}
Notice file:// changed to http:// in the URL constructor.
Now comes in jax-ws-catalog.xml. Without jax-ws-catalog.xml jax-ws will indeed try to load the WSDL from the location
http://localhost/wsdl/SOAService.wsdland fail, as no such WSDL will be available.
But with jax-ws-catalog.xml you can redirect jax-ws to a locally packaged WSDL whenever it tries to access the WSDL @
http://localhost/wsdl/SOAService.wsdl.
Here's 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>
What you are doing is telling jax-ws that when ever it needs to load WSDL from
http://localhost/wsdl/SOAService.wsdl, it should load it from local path wsdl/SOAService.wsdl.
Now where should you put wsdl/SOAService.wsdl and jax-ws-catalog.xml ? That's the million dollar question isn't it ?
It should be in the META-INF directory of your application jar.
so something like this
ABCD.jar |__ META-INF |__ jax-ws-catalog.xml |__ wsdl |__ SOAService.wsdl
This way you don't even have to override the URL in your client that access the proxy. The WSDL is picked up from within your JAR, and you avoid having to have hard-coded filesystem paths in your code.
More info on jax-ws-catalog.xml http://jax-ws.java.net/nonav/2.1.2m1/docs/catalog-support.html
Hope that helps
One other approach that we have taken successfully is to generate the WS client proxy code using wsimport (from Ant, as an Ant task) and specify the wsdlLocation attribute.
<wsimport debug="true" keep="true" verbose="false" target="2.1" sourcedestdir="${generated.client}" wsdl="${src}${wsdl.file}" wsdlLocation="${wsdl.file}">
</wsimport>
Since we run this for a project w/ multiple WSDLs, the script resolves the $(wsdl.file} value dynamically which is set up to be /META-INF/wsdl/YourWebServiceName.wsdl relative to the JavaSource location (or /src, depending on how you have your project set up). During the build proess, the WSDL and XSDs files are copied to this location and packaged in the JAR file. (similar to the solution described by Bhasakar above)
MyApp.jar
|__META-INF
|__wsdl
|__YourWebServiceName.wsdl
|__YourWebServiceName_schema1.xsd
|__YourWebServiceName_schmea2.xsd
Note: make sure the WSDL files are using relative refrerences to any imported XSDs and not http URLs:
<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>
In the generated code, we find this:
/**
* 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;
}
}
Perhaps this might help too. It's just a different approach that does not use the "catalog" approach.
Thanks a ton for Bhaskar Karambelkar's answer which explains in detail and fixed my issue. But also I would like to re phrase the answer in three simple steps for someone who is in a hurry to fix
wsdlLocation= "http://localhost/wsdl/yourwsdlname.wsdl"
Create an xml file jax-ws-catalog.xml under META-INF as below
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog"
prefer="system">
<system systemId="http://localhost/wsdl/yourwsdlname.wsdl" uri="wsdl/yourwsdlname.wsdl" />
</catalog>
Now package your jar. No more reference to the local directory, it's all packaged and referenced within
For those who are still coming for solution here, the easiest solution would be to use <wsdlLocation>
, without changing any code. Working steps are given below:
src/main/resource
In pom file, add both wsdlDirectory and wsdlLocation(don't miss / at the beginning of wsdlLocation), like below. While wsdlDirectory is used to generate code and wsdlLocation is used at runtime to create dynamic proxy.
<wsdlDirectory>src/main/resources/mydir</wsdlDirectory>
<wsdlLocation>/mydir/my.wsdl</wsdlLocation>
Then in your java code(with no-arg constructor):
MyPort myPort = new MyPortService().getMyPort();
For completeness, I am providing here full code generation part, with fluent api in generated code.
<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>
For those of you using Spring, you can simply reference any classpath-resource using the classpath-protocol. So in case of the wsdlLocation, this becomes:
<wsdlLocation>classpath:META-INF/webservice.wsdl</wsdlLocation>
Note that is not standard Java behavior. See also: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/resources.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With