The Java JAX-RPC implementation used to create simple to use web service clients, where developer can easily change the web service endpoint as shown below-
MyWsImpl stub = new MyWsImplService_Impl().getXXX();
((Stub) stub)._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, "http://myHost/myWs/myWs");
See this entry for details about building JAX-RPC web services.
The JAX-WS has changed the way it generates the clients. As a general practice people keep the WSDL along with their code and create the client side stubs at the build time. The JAX-WS hard codes the WSDL path in the client stub. See the one such generated code below-
package cache;If one tries to create an instance of client using the default constructor then it looks for the WSDL file at the location hard coded in the class and might fail with FileNotFoundException. The workaround for this problem is to call the another consturcutor, passing the endpoint URL and QName. Creating this QName is quite annoying and also that may change in future changes to WSDL. Then what is the easy wayout?
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebServiceClient;
@WebServiceClient(name = "MyServiceImplService", targetNamespace = "http://c.b.a/", wsdlLocation = "file:/D:/Test/temp/wsdl/MyServiceImplService.wsdl")
public class MyServiceImplService extends Service {
private final static URL MYSERVICEIMPLSERVICE_WSDL_LOCATION;
private final static Logger logger = Logger
.getLogger(MyServiceImplService.class.getName());
static {
URL url = null;
try {
URL baseUrl;
baseUrl = MyServiceImplService.class.getResource(".");
url = new URL(baseUrl,
"file:/D:/Test/temp/wsdl/MyServiceImplService.wsdl");
} catch (MalformedURLException e) {
logger.warning("Failed to create URL for the wsdl Location: 'file:/D:/Test/temp/wsdl/MyServiceImplService.wsdl', retrying as a local file");
logger.warning(e.getMessage());
}
MYSERVICEIMPLSERVICE_WSDL_LOCATION = url;
}
public MyServiceImplService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public MyServiceImplService() {
super(MYSERVICEIMPLSERVICE_WSDL_LOCATION, new QName("http://c.b.a/",
"MyServiceImplService"));
}
}
If you look closely at the web service client, it has an annotation @WebServiceClient, which has all the information to create the QName dynamically.
WebServiceClient ann = MyServiceImplService.class
.getAnnotation(WebServiceClient.class);
MyServiceImplService service = new MyServiceImplService(
new URL("ENDPOINT URL OF MY SERVICE"),
new QName(ann.targetNamespace(), ann.name()));
Now it looks pretty simple, is not it?

9 Comments:
Hello Vinod,
I think there must be a way to ensure that the entry in the .wsdl file is populated correctly
ie
the entry
soap:address location="REPLACE_WITH_ACTUAL_URL"
is the culprit .
the "REPLACE_WITH_ACTUAL_URL" should be replaced dynamically at runtime - as the the wsdl gets rebuilt everytime, it becomes tedious to do a cut and paste of this entry .
Any thoughts please , much appreciated
Kasi,
'REPLACE_WITH_ACTUAL_URL' is replaced at runtime, you can test it by viewing WSDL (using service URL) of a deployed application in browser. If WSDL is bundled with client application then it has to be changed programmatically while invoking service methods.
thats, cool. Thx
I am attempting a JAX WS Client w/ a local wsdl. The web service client class looks very similar to your example. When I define the URL w/ the local path of the wsdl I receive the error - "main" java.lang.IllegalArgumentException: getNamespaceURI(String prefix) is called with a null prefix. When I put the Endpoint URL in instead, I get the error - com.sun.xml.ws.wsdl.parser.InaccessibleWSDLException: 2 counts of InaccessibleWSDLException. One last thing, the code was generated using the web service client builder in MyEclipse 6.6 . Any help would be greatly appreciated.
Not sure about first error, but second one clearly mentions that it was not able to access the WSDL.
If you can post the code and versions of the JAX-WS other technologies being used, that would help in finding a solution.
I am using jax_ws 2.1. I have tested the web service as well w/ soap UI so I know that it is functioning. Here is the source code.
package com.aaa.Cybersource;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
/**
* This class was generated by the JAX-WS RI. JAX-WS RI 2.1.3-hudson-390-
* Generated source version: 2.0
*
* An example of how this class may be used:
*
*
* ElectronicPaymentService service = new ElectronicPaymentService();
* ElectronicPaymentPortType portType = service.getElectronicPaymentPort();
* portType.runCreditCardTransaction(...);
*
*
*
*
*/
@WebServiceClient(name = "ElectronicPaymentService",
targetNamespace = "http://XXXXXXXXXXX.com/electronicpayment/2008/08/15",
wsdlLocation = "file:/C:/XXXXXXXX/epayment2/ePayment/wsdl/electronicpayment/ElectronicPaymentServiceImplementationCC.wsdl")
public class ElectronicPaymentService extends Service {
private final static URL ELECTRONICPAYMENTSERVICE_WSDL_LOCATION;
private final static Logger logger = Logger
.getLogger(com.XXX.Cybersource.ElectronicPaymentService.class
.getName());
static {
System.out.println("ElectronicPaymentService begin 2:");
URL url = null;
try {
URL baseUrl;
baseUrl = com.XXX.Cybersource.ElectronicPaymentService.class
.getResource(".");
url = new URL(
baseUrl, "https://111.11.111.111:1111/ElectronicPaymentService.asmx");
// "file:/C:/XXXXXX/epayment2/ePayment/wsdl/electronicpayment/ElectronicPaymentServiceImplementationCC.wsdl");
} catch (MalformedURLException e) {
logger
.warning("Failed to create URL for the wsdl Location: 'file:/C:/XXXXX/epayment2/ePayment/wsdl/electronicpayment/ElectronicPaymentServiceImplementationCC.wsdl', retrying as a local file");
logger.warning(e.getMessage());
}
// URL url = null;
// ClassLoader classloader = Thread.currentThread().getContextClassLoader();
// url = classloader.getResource("WEB-INF/wsdl/electronicpayment/ElectronicPaymentServiceImplementationCC.wsdl");
ELECTRONICPAYMENTSERVICE_WSDL_LOCATION = url;
System.out.println("ElectronicPaymentService url: "+url.toString());
}
public ElectronicPaymentService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public ElectronicPaymentService() {
super(ELECTRONICPAYMENTSERVICE_WSDL_LOCATION, new QName(
"http://XXXXXXXXXXX.com/electronicpayment/2008/08/15",
"ElectronicPaymentService"));
}
/**
*
* @return returns ElectronicPaymentPortType
*/
@WebEndpoint(name = "ElectronicPaymentPort")
public ElectronicPaymentPortType getElectronicPaymentPort() {
return super.getPort(new QName(
"http://XXXXXXXXXXX.com/electronicpayment/2008/08/15",
"ElectronicPaymentPort"), ElectronicPaymentPortType.class);
}
}
My problem is solved for the naccessibleWSDLException. As it turned out the port in the endpoint was incorrect. Once that was corrected I got it working.
QUOTE:
Kasi,
'REPLACE_WITH_ACTUAL_URL' is replaced at runtime, you can test it by viewing WSDL (using service URL) of a deployed application in browser. If WSDL is bundled with client application then it has to be changed programmatically while invoking service methods.
What do you mean by programmatically? Meaning writing onto the xml .wsclient file?
@cancelledout,
Programmatically means something like-
ServiceImplService service = new MyServiceImplService(new URL("ENDPOINT URL OF MY SERVICE"), new QName(ann.targetNamespace(), ann.name()));
Post a Comment