【问题标题】:Java InaccessibleWSDLException while accessing WSDL through client stubs通过客户端存根访问 WSDL 时出现 Java InaccessibleWSDLException
【发布时间】:2013-10-08 11:32:43
【问题描述】:

我正在尝试为 Exchange Web 服务编写自定义 Java 客户端。 我已经使用 wsimport 工具生成了客户端存根,正如 EWS 的 Services.wsdl 文件中的 here 所解释的那样。现在我已经编写了使用这些存根的代码。我收到以下异常:

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)

正如我们在上面看到的ExchangeDevelopmentTest 是一个使用另一个类ExchangeAuthenticator 的客户端,该类又使用生成的客户端存根ExchangeWebService。但是在堆栈跟踪中,我收到了来自未知来源的错误,大概是 JDK 的 JAR。

IOException 表示它得到了HTTP response code: 401,即用于未经授权的访问。但是我已经正确指定了用户名和密码,并且还在密钥库中包含了所需的证书。我完全没有方向,这个异常来自哪里。

我写的类的代码:

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

由 JAX-WS 使用 wsimport 工具生成,删除了其他构造函数和方法。仅保留第 58 行调用 super(此处为 Service 类)构造函数的构造函数。

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

【问题讨论】:

    标签: java wsdl jax-ws exchangewebservices


    【解决方案1】:

    为什么在您可以拥有本地副本的情况下访问远程 WSDL 文档文件(和模式文件)?当然,访问端点仍然需要安全性。

    首先,根据环境需要类加载器。

    // Java EE Enviroment
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    
    // Java Standalone Enviroment
    ClassLoader cl = ClassLoader.getSystemClassLoader();
    

    接下来,在本地存储项目中 WSDL 文档文件(以及方案文件,如果需要)的副本。

    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();
    

    如果访问webservice端点需要认证,最基本的形式如下:

    BindingProvider provider = (BindingProvider) port;
    Map<String, Object> context = provider.getRequestContext();
    context.put(BindingProvider.USERNAME_PROPERTY, username);
    context.put(BindingProvider.PASSWORD_PROPERTY, password);
    

    如果你需要处理证书之类的事情,最好看看Securing WebLogic Web Services

    【讨论】:

      【解决方案2】:

      你是这样添加用户名和密码的吗?

          ShopingCart sc = scs.getShopingCartPort();
          Map requestContext = ((BindingProvider)sc).getRequestContext();
          requestContext.put(BindingProvider.USERNAME_PROPERTY, userName);
          requestContext.put(BindingProvider.PASSWORD_PROPERTY, password);
      

      您尚未提供有问题的客户代码。你在使用代理吗?然后你必须在上面提供你的代理用户名和密码。

      【讨论】:

      • 我已经添加了代码。如您所见,ExchangeDevelopmentTest 包含main()。在ExchangeAuthenticatorExchangeWebService exchangeWebService... 行中,我得到了异常。这一行只是调用ExchangeWebService 类的构造函数之一(由wsimport 工具生成),后者又调用super(此处为Service 类)构造函数。在调试时我无法进入这个类的源代码(显然)。
      • 在第二个参数的构造函数中,使用自动生成的代码提供的 QName。 new QName("http://schemas.microsoft.com/exchange/services/2006/messages", "ExchangeWebService")
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-13
      • 1970-01-01
      • 2012-09-17
      • 1970-01-01
      • 2013-01-02
      • 1970-01-01
      • 2021-01-23
      相关资源
      最近更新 更多