Java inaccessible wsdlexception when accessing WSDL through client stub
I'm trying to write a custom java client for exchange web services
Exception in thread "main" com.sun.xml.internal.ws.wsdl.parser.InaccessibleWSDLException: 2 counts of InaccessibleWSDLException. java.io.IOException: Got Server returned HTTP response code: 401 for URL: https://host.domain.com/ews/Services.wsdl while opening stream from https://host.domain.com/ews/Services.wsdl java.io.IOException: Got Server returned HTTP response code: 401 for URL: https://host.domain.com/ews/Services.wsdl?wsdl while opening stream from https://host.domain.com/ews/Services.wsdl?wsdl at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.tryWithMex(UnkNown Source) at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.parse(UnkNown Source) at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.parse(UnkNown Source) at com.sun.xml.internal.ws.client.WSServiceDelegate.parseWSDL(UnkNown Source) at com.sun.xml.internal.ws.client.WSServiceDelegate.<init>(UnkNown Source) at com.sun.xml.internal.ws.client.WSServiceDelegate.<init>(UnkNown Source) at com.sun.xml.internal.ws.spi.ProviderImpl.createServiceDelegate(UnkNown Source) at javax.xml.ws.Service.<init>(UnkNown Source) at com.microsoft.schemas.exchange.services._2006.messages.ExchangeWebService.<init>(ExchangeWebService.java:58) at com.xyz.abc.EWSJavaAPI.ExchangeAuthenticator.getExchangeServicePort(ExchangeAuthenticator.java:33) at com.xyz.abc.test.ExchangeDevelopmentTest.main(ExchangeDevelopmentTest.java:35)
As we saw above, exchange development test is a client that uses another class, exchange authenticator, which in turn uses the generated client stub exchange web service But in the stack trace, I got an error from unknow sources, probably the jar of JDK
IOException indicates that it has HTTP response code: 401 for unauthorized access However, I have specified the user name and password correctly and included the required certificate in the keystore The source of this anomaly, I have no direction at all
The code of the class I wrote:
ExchangeAuthenticator
public class ExchangeAuthenticator {
/**
* Obtains an authenticated ExchangeServicePortType with given credentials.
*
*/
public ExchangeServicePortType getExchangeServicePort(String username,String password,String domain,URL wsdlURL) throws MalformedURLException {
// Concatinate our domain and username for the UID needed in authentication.
String uid = "domain" + "\\" + "uname";
// Create an ExchangeWebService object that uses the supplied WSDL file,wsdlURL.
ExchangeWebService exchangeWebService = new ExchangeWebService(wsdlURL,new QName("<a href=\"http://schemas.microsoft.com/exchange/services/2006/messages\">http://schemas.microsoft.com/exchange/services/2006/messages</a>","ExchangeWebService"));
ExchangeServicePortType port = exchangeWebService.getExchangeWebPort();
// Supply your username and password when the ExchangeServicePortType is used for binding in the SOAP request.
((BindingProvider)port).getRequestContext().put(BindingProvider.USERNAME_PROPERTY,uid);
((BindingProvider)port).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY,password);
return port;
}
}
ExchangeDevelopmentTest
public class ExchangeDevelopmentTest {
public static void main (String[] args) {
ExchangeAuthenticator exchangeAuthenticator = new ExchangeAuthenticator();
// Print statement so we can easily see where our statements start in the Java console.
System.out.println("Let's get started!");
try {
// Create a URL object which points at the .wsdl we deployed in the prevIoUs step.
URL wsdlURL = new URL("https://172.17.245.196/ews/Services.wsdl");
//URL wsdlURL = new URL("<a href=\"https://172.17.245.196/ews/Services.wsdl\">https://172.17.245.196/ews/Services.wsdl</a>");
// Call to the class we just created to return an ExchangeServicePortType with authentication credentials.
ExchangeServicePortType port = exchangeAuthenticator.getExchangeServicePort("uname","password@123","domain",wsdlURL);
// Prints out the default toString() for the ExchangeServicePortType.
System.out.println(port.toString());
} catch (MalformedURLException ex) {
// Catch any errors that may occur.
Logger.getLogger(ExchangeDevelopmentTest.class.getName()).log(Level.SEVERE,null,ex);
System.out.println(ex.getMessage()+"\n"+ex.getStackTrace());
}
}
}
ExchangeWebService
Generated by Jax - WS using wsimport tool, other constructors and methods are deleted Only the constructors in the fifty-eighth row call the constructor of super (here Service class).
@WebServiceClient(name = "ExchangeWebService",targetNamespace = "http://schemas.microsoft.com/exchange/services/2006/messages",wsdlLocation = "file:/C:/Services.wsdl")
public class ExchangeWebService extends Service
{
private final static URL EXCHANGEWEBSERVICE_WSDL_LOCATION;
private final static WebServiceException EXCHANGEWEBSERVICE_EXCEPTION;
private final static QName EXCHANGEWEBSERVICE_QNAME = new QName("http://schemas.microsoft.com/exchange/services/2006/messages","ExchangeWebService");
static {
URL url = null;
WebServiceException e = null;
try {
url = new URL("file:/C:/workspace/Server%20files/Client%20files/Services.wsdl");
} catch (MalformedURLException ex) {
e = new WebServiceException(ex);
}
EXCHANGEWEBSERVICE_WSDL_LOCATION = url;
EXCHANGEWEBSERVICE_EXCEPTION = e;
}
//other constructos & methods removed
//line 58
public ExchangeWebService(URL wsdlLocation,QName serviceName) {
super(wsdlLocation,serviceName);
}
}
Solution
Why access remote WSDL document files (and schema files) when you can have a local copy? Of course, access endpoints still need security
First, you need to load classes according to your environment
// Java EE Enviroment ClassLoader cl = Thread.currentThread().getContextClassLoader(); // Java Standalone Enviroment ClassLoader cl = ClassLoader.getSystemClassLoader();
Next, a copy of the WSDL document file (and the schema file, if needed) is stored locally in the project
URL wsdlLocation = cl.getResource("com/mahesha999/ExchangeWebService.wsdl");
QName qName = new QName(
"http://schemas.microsoft.com/exchange/services/2006/messages","ExchangeWebService"
);
ExchangeWebService exchangeWebService = new ExchangeWebService(wsdlLocation,qName);
ExchangeServicePortType port = exchangeWebService.getExchangeWebPort();
If authentication is required to access the web service endpoint, the basic form is as follows:
BindingProvider provider = (BindingProvider) port; Map<String,Object> context = provider.getRequestContext(); context.put(BindingProvider.USERNAME_PROPERTY,username); context.put(BindingProvider.PASSWORD_PROPERTY,password);
If you need to handle certificates, etc., you'd better take a look at secure Weblogic web services
