Web 服务错误信息故障诊断

使用 IBM Rational Application Developer 7.5.4 和 IBM WebSphere Application Server 6.1 来查找和修复问题

Comments

引言

您对使用 IBM® Rational® Application Developer 7.5.4 版本与 IBM® WebSphere® Application Server 6.1 版本来开发一个 Web 服务平台是否做好了准备?或者您是否注意到了错误信息并没有告诉您关于问题来源的详细信息?您是否需要进行调试并找到这些问题的来源呢?本文将会帮助您找到一个解决这些问题的可实施方法。

您将会学到基本的技术,使用这些 IBM 工具来分析与 Web 服务相关的各种问题。本文强调了程序的环境层次上的问题,以及 Web 服务配置期间可能出现的问题。但是,本文并没有包含技术或者与框架相关的问题,以及与 Web 服务相关的问题,因为根据程序的需求不同这些情况也会发生变化。

如果您想要得到关于本文的更多信息,那么您对 WebSphere 程序服务器与 Rational Application Developer 创建应该有一个基本的了解;但是,我们的关注点是那些描述场景细节的部分,尽可能多地使用本文中演示以解决该问题。

范例 Web 服务

您要构建一个范例 Web 服务,对于通过 Rational Application Developer 7.5.4 来调试常见问题以进行演示将会十分有用

您将要生成一个名为 DisplayUnit 的范例 Web 服务,它用于显示关于需求基础的信息。显示单元 Web 服务使用名为 Address.java、Customer.java 和 DisplayUnit.java 的三种 Java 文件。接下来的代码清单 1、2、3 包含了三个 Java 文件:代码清单 1 是 Customer.java,代码清单 2 是 Address.java,而代码清单 3 是 DisplayUnit.java。

清单 1. Customer.java
package com.demo.display;
public class Customer {
	private String name;
	private Address ad;
	public Address getAddress() {
		ad = new Address();
		ad.setCity("SS1");
		ad.setHouseNo("12");
		ad.setZipCode("215462");
		return ad;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public boolean setAddress(Address ad1) {
		this.ad = ad1;
		return true;
	}
	}
清单 2. Address.java
package com.demo.display;

public class Address {
	private String city;
	private String zipCode;
	private String houseNo;
	public String getCity() {
		return city;
	}
	public void setCity(String city) {
		this.city = city;
	}
	public String getHouseNo() {
		return houseNo;
	}
	public void setHouseNo(String houseNo) {
		this.houseNo = houseNo;
	}
	public String getZipCode() {
		return zipCode;
	}
	public void setZipCode(String zipCode) {
		this.zipCode = zipCode;
	}
}
清单 3. DisplayUnit.java
package com.demo.display;
import com.demo.display.Customer;
public class DisplayUnit {
	private String msg;
	private int id;
        private Address ad;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getMsg() {
		return msg;
	}
	public void setMsg(String msg) {
		this.msg = msg;
	}
	public Customer getCustomerDetails() {
		Customer cust = new Customer();
		cust.setName("ABC");
		cust.setAddress(cust.getAddress());
		return cust;
	}
	public Address getAddress() {
		Customer cust = new Customer();
		System.out.println(cust.getAddress().getCity());
		return cust.getAddress();
	}
}

您所要创建的另一个范例 Web 服务是 Employee 信息。它叫做 GenerateDetails ,而且它使用如代码清单 4、5 和 6 所示的文件。

清单 4. GenerateDetails.java
package com.service;

import com.employee.Address;
import com.employee.Employee;

public class GenerateDetails {
		public Employee showEmployeeDetails()
	{
	Employee emp = new Employee();
	emp.setId(1);
	emp.setName("John");
	emp.setId(2);
	emp.setName("Tom");
	Address addr = new Address();
	addr.setCountry("XXX");
	addr.setLocation("YYY");
	addr.setState("ZZZ");
	addr.setZipCode("1234");
	emp.setAddr(addr);
		return emp;
	}
}
清单 5. Employee.java
package com.employee;

public class Employee  {
    private int id;
    private java.lang.String name;
    private com.employee.Address addr;

    public Employee() {
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public java.lang.String getName() {
        return name;
    }
    public void setName(java.lang.String name) {
        this.name = name;
    }
    public com.employee.Address getAddr() {
        return addr;
    }
    public void setAddr(com.employee.Address addr) {
        this.addr = addr;
    }
}
清单 6. Address.java
package com.employee;

public class Address {
	public Address()
	{}
	private String zipCode;
	private String Location;
	private String Country;
	private String State;
	public String getCountry() {
		return Country;
	}
	public void setCountry(String country) {
		Country = country;
	}
	public String getLocation() {
		return Location;
	}
	public void setLocation(String location) {
		Location = location;
	}
	public String getState() {
		return State;
	}
	public void setState(String state) {
		State = state;
	}
	public String getZipCode() {
		return zipCode;
	}
	public void setZipCode(String zipCode) {
		this.zipCode = zipCode;
	}
}

这个假设您已经知道了怎样通过 Rational Application Developer 来创建一个范例的 Web 服务。但是,在有些情况下,您必须接受一些奇怪的错误。接下来的章节讨论了这些问题并继续使用该范例 Web 服务的例子。

“拒绝连接”信息

(DisplayUnit webservice)

这种类型错误的发生,通常是由于服务端的配置不正确造成的。最普通的来源是部署程序的程序服务器处的配置。如果您遇到了一种“拒绝连接”错误,那么您可以使用 Web 服务测试选项来试着测试一些 WSDL( Web 服务描述语言),也就是 Rational Application Developer 所提供的“使用 Web 服务浏览器来进行测试 ”选项。检查以下的调查点,以调试拒绝连接的错误:

检查Check whether the WebSphere 程序服务器在 Rational Application Developer 服务器的概述中是否注册过。如果它尚未配置过,那么您可以按照下面的指南,来为 Rational Application Developer 中的 WebSphere 创建一个服务器概述(对于当前的范例)。

  1. 选择 Window > Show View > Other 选项(参见图 1),然后搜索并选择 Server 视图,然后选择 Servers
图 1. Rational Application Developer 7.5.4 中的 Server 视图
指向 Servers 视图的下拉菜单
指向 Servers 视图的下拉菜单
  1. 在 Servers 视图中,点击 New Server(图 2),并提供程序服务器的安装路径来配置程序。在本例中:
    C:\Program Files\IBM\WebSphereV6.1\AppServer
图 2. 在 Rational Application Developer 7.5.4 中定义一个新的服务器实例
WebSphere v6.1 服务器作为新服务器选中
WebSphere v6.1 服务器作为新服务器选中

定义程序服务器

按照下面的步骤,从图 3 到图 7,来在 Rational Application Developer 7.5.4 中定义程序服务器:

  1. New Server 窗口中(如图 2 所示),点击 Installed Runtimes 按钮。
  2. Preferences 窗口中,点击 Add 按钮。
  3. 在视图中,点击 Add 并选择 WebSphere Application Server v6.1
图 3. 选择运行时程序服务器版本
添加运行时服务器实例
添加运行时服务器实例
  1. New Server Runtime 窗口中,选择 WebSphere Application Server 的安装目录,然后点击 Finish
图 4. 选择 WebSphere Application Server 的安装目录
添加的 New Server Runtime 具体内容
添加的 New Server Runtime 具体内容
  1. 确认新程序服务器是否列在了 Installed Runtimes 之中。
图 5. 确认安装的服务器
Preferences 窗口中列出的 Installed Runtime
Preferences 窗口中列出的 Installed Runtime
  1. 在安装的运行时环境中定义新服务器之后,您可以点击 New Server 窗口中的 Next(图 2)。确认 WebSphere 配置并点击 Finish
图 6. WebSphere Application Server V6.1 配置设置
WebSphere 服务器设置窗口
WebSphere 服务器设置窗口
  1. 在您点击 Finish 按钮之后,如图 6 所示,您将会在 Rational Application Developer 的 Server 视图中看到配置好的程序服务器(图 7)。
图 7. Server 状态
WebSphere Servers 项
WebSphere Servers 项
  1. 从 Rational Application Developer 服务器的概述中,确认程序是否已经启动。点击 Rational Application Developer 的 Server 视图中所列出的程序。如果程序已经安装了,并且在配置的程序服务器上已经启动了,那么您将会在 Server 视图中看到 已启动 状态(参见图 8,片段 3)。
    注意: Server 视图中所列出的程序服务器应该通过右击服务器的名字并选择 Start 选项来启动。否则,它就不会在里面列出任何的程序(参见图 7)。

从图 8 的首个界面片段(1)中,它显示了 WebSphere 与 Web 服务状态校检 ,您可以在程序服务器中看到没有启动的程序(因为在状态部分中没有显示任何的状态)。这也是产生“拒绝连接”信息的原因中的一个。如果注册的程序服务器是只在机器上运行的 WebSphere 实例,那么您可以试着登录到程序服务器的管理员操控台上,并从服务器操控台上重启程序。如果在重启时问题仍然存在,那么您最好重新部署 Web 服务,因为程序服务器现在没有显示任何关于停止状态的信息。相反,它显示了一个空白的状态,所以您就可以确定程序遭到了适当的终止,而且并没有产生什么内部性(特定程序)的问题。

图 8. WebSphere 与部署的 Web 服务项目状态(3 个视图)
WebSphere 与 Web 服务状态校检
WebSphere 与 Web 服务状态校检

正如 WebSphere 与 Web 服务状态所示的那样(图 8 中的视图 2)。如图您遇到一个服务器状态,在此状态下,没有程序的状态,很明显在程序服务器中没有部署的程序。您可以使用 Rational Application Developer 来试着部署程序:右击主服务类然后点击 创建 Web 服务。

如果您想要得到更多的信息,那么您可以查看 IBM® Redbooks® Rational Application Developer 版本 7 的编程指南,IBM WebSphere 版本 6 对于开发与部署的 Web 服务手册,或者关于使用 Rational Application Developer 来创建 Web 服务的 IBM 指南。链接位于 Resources 部分之中。

就算您部署了程序,但是不是很确定在 WebSphere 程序服务器的目录下没有创建相关的文件夹,那么图 9 中所示的配置将会帮助您在服务器的相应位置处部署程序。请选择图片中所提到过的选项:WebSphere 程序服务器配置

图 9. WebSphere Application Server 配置设置
WebSphere Server Configuration 设置
WebSphere Server Configuration 设置

如果强调的选项(是一个矩形的框)尚没有被激活,那么这就是为什么捆成一个 EAR(企业档案)文件的 Web 服务没有复制到服务器位置的主要原因。

为了加速调试和测试,如果您在 Rational Application Developer IDE 上安装有一个测试服务器,那么您就可以避免大多数的服务器配置延迟了。如果您稍后想要安装该特性的话,那么您可以在安装期间选择该特性,或者使用 Rational Installation 管理器。安装一个测试服务器会导致服务器的自动创建,以及新工作区中相关默认概述的创建。

不能定位一个有效的 EngineConfigurationFactory

(GenerateDetails web service)

有时,在调用 Web 服务类时(错误描述与以下的错误很相似),您可能会接受以下的错误:

E WSWS1002E: An error occurred while processing the
Web services deployment descriptor for module:
WebServiceProject.war with error:
java.lang.ClassNotFoundException:
com.details.employee.Employee
E com.ibm.ws.webservices.engine.configuration.
EngineConfigurationFactoryFinder$1 run
WSWS3345E: Error: Unable to locate
a valid EngineConfigurationFactory.

您的基本调查应该包含以下的几点:

  • 描述 ClassNotFoundException:
    的错误会检查什么类文件出现在服务器的位置中。检查所有需要的类是否位于类文件夹中。例如,图 10 显示了,从 Navigator 视图的 Web 服务下面中,Employee 类不会显示在 Web 服务项目之下,当您试着构建一个 Web 服务时,这些 Web 服务项目会得到创建。这种类型的错误并没有出现。但是,如果您遇到了这种类型的错误,那么您交替确认它的类位置。
图 10. Navigator 视图中的网络视图项目
Navigator 视图中的 Web 服务
Navigator 视图中的 Web 服务
  • 如果您遇到了 EngineConfigurationFactory 错误,它不会告诉您关于什么地方出现问题的信息:

    第一步是手动地确认所有类文件的位置。如果不是所有的文件都显示了出来,那么您需要重新配置您的程序,这样程序服务器就会在 Web 服务创建期间找到所有需要的类。当 Web 服务生成期间,有一些运行时配置相关的 XML 文件没有得到适当的写入时,这种情况通常都会发生。您还可以打开这些 XML 文件来交替确认;但是,不管何时您重新部署 Web 服务时,新内容都会发生更改。如果您重新部署整个的 Web 服务程序,那么这是一个很好的实践,去确保所有的运行时生成的文件(特定于程序服务器)都得到了创建。

    例如,在范例 Web 服务中,我们正在使用的是 JAX-RPC。如果您想要在实施类中添加新的操作,并想要重新部署它,有时,就算生成了 WSDL,它会不会生成适当的串列化及非串列化文件。如果您一直在编辑私人文件,而不用重新确认或者公布 Web 服务 WSDL 文件,那么产生这种例外情况的几率就会上升。例如,在 JAX-RPC 的情况下,找到 webservices.xml 文件以及相应的 WSDD 文件。您要试着重新部署 Web 服务。例如,在 JAX-RPC Web 服务的情况下,右击 Java EE 然后点击 Prepare for Deployment 以生成 Java 串列化和非串列化文件。

您好,这是一项 Web 服务!

(GenerateDetails web service)

如果您在使用 Web 服务 URL 来确认 Web 服务状态良好且正在运行,那么您会看到默认的 Web 服务信息,但是,如果您不能调用这种方法,那么您需要研究一下出现这种问题的原因。还有一种场景,如果您 ping Web 服务的 URL,那么您会得到一条信息声称“您好,这是一项 Web 服务!”,但是对于暴露的 Web 服务方法它不会产生任何的结果。这种类型的信息通常意味着 Web 服务现在运行良好。但是,您可能还会遇到一种情况,那就是您的 Web 服务还在运行,但是却不能处理到来的请求。这种类型的问题通常是由于配置文件以及 Web 服务类之间的差异所造成的。

您可以从运行的程序上的部署 Web 服务状态校检(图 11 显示“Status: Started”)和 Web 服务状态请求校检处进行查看,而且,如果您 ping Web 服务的 URL,那么就会显示一条信息“您好,这是一项 Web 服务!”

图 11. 部署的 Web 服务项目状态
安装的 Web 服务项目状态校检
安装的 Web 服务项目状态校检
图 12. 运行模式下部署的 Web 服务状态
 Web 服务状态请求校检
Web 服务状态请求校检

您可以使用一些暴露的 Web 服务方法,来检查您是否可以接受响应,来调查问题。除了这一点,通过日志您要试着确认,当您使用 Web 服务时程序服务器日志目录中都有什么内容。

在 SystemOut.log 中可以找到 Employee 类的错误描述:

WSWS3034E: Error: The OperationDesc for getName was not matched
to a method of com.details.employee.Employee.
Debug:name: services/Employee
implClass: class com.details.employee.Employee

正如在日志中所出现的那样,getName 方法签名与 WSDL 或者程序服务器生成的映射 XML 并不相匹配。

java.lang.Exception: WSWS3352E: 错误:不能找到一个与 WSDD 操作相匹配的 Java 操作

(GenerateDetails web service)

当在 Web 服务实施类中不能找到服务定义时,这种类型的错误通常会发生;但是,它的引用却一直保存在 Web 服务配置文件中(例如,在 WSDL 文件或者运行时生成的 XML 映射文件中)。当您忘记从相关的文件中删除引用时这种情况通常都会发生(如果您做手动的更新时这种情况发生的几率会上升)。使用 Rational Application Developer 来重新生成 Web 服务,可以解决这种类型的问题,由于配置和服务类的差异会使得这种问题出现的机会增多。

SRVE0255E:处理本地主机的 WebGroup/Virtual Host:9080 尚未定义

(GenerateDetails web service)

正如图 13 所示,当 Web 服务在程序服务器中没有得到适当的部署,或者它在主机上停止工作或者在程序服务器上没有运行时,这种类型的错误通常会发生。重新启动 Web 服务会解决这个问题。但是,如果您正在面对这样一个问题时,那么您就要确认 Web 服务在程序服务器上得到了正确的部署(如果不是,就重新部署它),并确认本地主机 9080 或者指定的端口是否打开以接受请求、

图 13. Web 服务调用期间的虚拟主机错误
网络浏览器中的虚拟主机错误
网络浏览器中的虚拟主机错误

您的调查点 应该包含程序服务器中的部署目录结构。确认 WSDL 和生成的 XML 映射文件是否包含了所有的 Web 服务操作。

通过切换至程序服务器的管理员操控台来检查端口设置。您还要检查 Java™ Enterprise Edition(JEE)部署描述器是否包含了程序的信息。

提示:
您可能需要确认 Web 服务项目的 Java EE 部署描述器。

错误、警告或者两者导致发布失败。请查看服务器日志以得到更多的细节信息。

(GenerateDetails web service)

在发布 Web 服务时,如果您遇到“发布 WSDL 时遇到错误”这种问题时,如图 14 所示,软件并不允许您去进一步地发布。检查错误的细节。在这种情况下,错误信息意味着它不能识别这个名字。我们通过查找创建它的目录的来源,通常会对该错误作出误判。但是,您需要确认 Web 服务试着解决名字问题以顺利发布。在这里的范例中,它会试着从 Web 服务项目中找到文件“Employee.java”,它从 Rational Application Developer 的 Web 服务项目中丢失了。在项目目录中放置该文件并重新发布它,可以解决这个问题。

不合适的部署描述器也有可能导致 Web 服务发布错误的发生。如果它是手工完成的,或者在运行时错误匹配配置期间,这种情况发生的几率会非常高。

图 14. 发布 WSDL 时发生的错误
WSDL Publishing 失败的错误
WSDL Publishing 失败的错误

com.ibm.ws.Web services.engine.deployment.wsdd.WSDDNonFatalException:

(GenerateDetails web service)

这种类型的问题(当您首次创建 Web 服务或者在对 Web 服务类作出更改之后,它不会适当反映出程序服务器的文件),如果您在使用 Web 服务时遇到了这种问题,那么您要确认该错误提到过的文件是否现在在程序服务器部署的程序路径之上。如果不是,那么您需要将 Web 服务重新部署在程序服务器上。从名为“ Web 服务生成的类”的屏幕截图(图 15)中可以很清晰地看到,这些文件没有在报告错误服务器的位置中列出(在 WebSphere Application Server 的 SystemOut.log 中显示出来了错误):

WSWS1002E: An error occurred while processing the
Web services deployment descriptor for module:
WebServiceProject.war with error:
com.ibm.ws.webservices.engine.
deployment.wsdd.WSDDNonFatalException:
java.lang.ClassNotFoundException:
com.employee.Address
图 15. Web 服务生成的类
 Web 服务运行时生成的类
Web 服务运行时生成的类

TypeMappingImpl.register 方法中所指定的 Null 串列化库

(GenerateDetails web service)

Web 服务对于复杂数据类型的对象生成产生问题,反过来,对象又使用其他的对象时,这种类型的问题通常都会发生。错误描述就像该输出一样(如 WebSphere Application Server 的 SystemOut.log 中显示的错误一样)。

WSWS1002E: An error occurred while processing the
Web services deployment descriptor for module:
WebServiceProject.war with error:
com.ibm.ws.webservices.engine.deployment.
wsdd.WSDDException: javax.xml.rpc.JAXRPCException:
WSWS3218E: Error: Null serializer factory specified in
the TypeMappingImpl.register method.
javax.xml.rpc.JAXRPCException: WSWS3218E: Error:
Null serializer factory specified in the
TypeMappingImpl.register method.

您的基本调查还应该包含以下的步骤:

  1. 确认在 Web 服务部署期间,没有创建的任何空白串列化和非串列化文件。
  2. 如果串列化和非串列化的文件显示了出来,那么您要确认类属性出现在这些文件之中。
  3. 从 WSDL 文件中确认复杂的对象是否包含了服务的引用。在 Web 服务生成期间,它有时候会发生,就算您从 Java 视角来定义复杂的对象时也是一样,在 WSDL 中它没有得到适当的反映。

如果在 Web 服务浏览器中您不能够看到复杂的对象细节

(DisplayUnit web service)

在一些情况下它会发生,就算您清晰地定义了复杂的对象结构,但是在测试 Web 服务客户端不能得到信息时,这种情况也会发生。

考虑一下以下的范例,因为从图 16 的 Web 服务浏览器的屏幕截图中,它清晰地显示了出来,在这里我们试着调用 getCustomerDetails Web 服务方法,它包含了地址的细节信息。但是,当我们在调用方法时,如果复杂的对象没有得到清晰的定义,那么我们可以找到 Address 信息没有出现在测试客户端中。所以我们需要进一步地去调查这个问题。

图 16. Web 服务 Explorer窗口
Web Service Explorer 窗口
Web Service Explorer 窗口

Rational Application Developer p提供了 WSDL 映射视图,您可以双击 WSDL 文件来找到它,正如您在 WSDL 视图设计模式下看到的那样(图 17)。

图 17. 设计模式下的 WSDL
设计模式下的 WSDL 视图
设计模式下的 WSDL 视图

这里的演示给出了关于 Web 服务所有暴露操作的完整信息。为了确认一个生成的 WSDL 是否有一个完整的对象属性 Address,您可以按照下面的步骤来进行操作:

  1. 点击 getCustomerDetails 以查看具体的信息。因为这种方法包含了 Java 文件中定义的 Address 类,生成的 WSDL 理想条件下包含有它。
  2. 点击方法右边的箭头。您可以清楚地从 WSDL 复杂对象属性”界面(图 18)中看到生成的 WSDL 并没有包含 Customer 中定义的 Address。这就是导致问题的原因所在。因此,您需要在生成的 WSDL 中定义 Address 类,并需要再次公布 Web 服务,这样它就可以为该对象创建串行化和非串行化的文件。
图 18. WSDL 复杂的对象属性
屏幕截图:Customer 类

总结

从这篇文章中,您已经学到了一些基本的故障排除技术,您可以将其与 Web 服务中的 Rational Application Developer 7.5.4 版本错误信息一起使用。本文可以帮助您快速的看清问题的实质,并帮助您调试一些初次看来不会出现的怪异问题。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Rational
ArticleID=630531
ArticleTitle=Web 服务错误信息故障诊断
publish-date=07192010