在ApacheGeronimo应用程序中实现和部署Web服务

现在,无论您的企业应用程序是部署在小型家庭商店中,还是跨多个领域的企 业基础设施的一部分,无论应用程序是否与他人协作,它都必须支持 Web 服务。

途径

现代企业往往是非常复杂的系统,每天要面对许多机会和挑 战。许多机会涉及到与其他系统和企业进行集成或协作。因此,明智的企业应用 程序开发人员要确保别的应用程序可以轻松地访问自己的应用程序。Web 服务就 是提供这种可访问性的好方式。

Apache Geronimo 应用服务器支持 Web 服务以及最新 Java™ 2 Platform, Enterprise Edition(J2EE)规范的其 他特性。为了演示 Geronimo 应用服务器中的 Web 服务支持,IBM Advanced Technology Solutions 团队已经决定改进一个软件模拟程序,这个程序模拟了简 单的银行场景,是为以前的一篇 developerWorks 文章 “使用 Geronimo 构建安全的企业基础设施”(developerWorks,2005 年 7 月)开发的。

本文使用的业务场景实现一个资金转帐用例。零售银行客户(用户)可以访问 这个应用程序,将资金从自己的帐户转出来,审计员可以监督所有银行事务。现 有的资金转帐应用程序得到了改进,允许 Web 服务使用 Simple Object Access Protocol/Hypertext Transfer Protocol(SOAP/HTTP)和简单的 Web 服务客户 机来提供后端功能。

什么是 Web 服务?

Web 服务是一段应用程序 业务逻辑,可以使用普遍存在的 Web 协议和数据格式(比如 HTTP 和 SOAP)来 执行。自从 J2EE 1.4 发布以来,Web 服务已经融入了 J2EE 中。在 J2EE 上下 文中,Web 服务被认为是后端实现的外观(facade) —— 后端实现 可能是 Enterprise JavaBean(EJB)或 servlet。下面的工件组成了 Web 服务 :

一个 Web Service Definition Language(Web 服务定义语言,WSDL)文档, 描述服务接口和端口。

一个服务端点接口,它由服务器部分实现,用于在客户机上调用服务方法。来 自 WSDL 的绑定映射到这个端点接口,WSDL 绑定是 WSDL 的一部分,定义了 Web 服务的协议。

Java API for XML-based RPC(JAX-RPC)描述符,包含从 XML 到 Java 技术 的不同映射,比如将来自 WSDL 文档的 XML Schema Definition(XSD)类型映射 到 Java 类型,以及将 XML 元素映射到端点接口方法参数。

服务实现 —— EJB 或 servlet。

Web 服务部署描述符 webservices.xml。

以下几节开发这些工件,为 Geronimo 构建一个支持 Web 服务的应用程序。

创建 Web 服务

首先,开发 Web 服务本身。为此,必须在同一个文件夹中创建以下工件。( 稍后给出每个步骤的细节。)

生成或开发 WSDL。在这个例子中,使用来自 Sun J2EE 参考实现的 wscompile 工具。

开发端点接口。它是基于 EJB 远程接口开发的。

用 JAX-RPC 映射将 WSDL 类型映射为 Java 类型。JAX-RPC 映射是使用 wscompile 工具生成的。

实现端点接口。

在部署描述符中配置 Web 服务引用。这包括在 web.xml 部署描述符中添加一 节。

下面详细描述每个步骤。

第一个步骤是在 WSDL 文件中描述 Web 服务。在这个例子中,因为 Web 服务 提供的功能与业务逻辑 EJB 相同,所以可以从 EJB 接口生成 WSDL,然后进行手 工编辑。[注意,到编写本文时,Geronimo 对于构建 J2EE Web 服务还没有完善 的工具支持(Axis 特定的 Web 服务例外,这种 Web 服务可以使用 Axis 工具生 成]。

要从端点接口生成 WSDL,必须先开发一个接口。这个接口声明 Web 服务实现 的方法。JAX-RPC 规范对这个接口有一些限制。简单地说,这个接口应该扩展 java.rmi.Remote —— 所有方法都声明为抛出 java.rmi.RemoteException。最 后,参数和返回值是 JAX-RPC 兼容的(在我们的例子中,它们是具有默认构造函 数的 JavaBean 和原始类型)。简单地说,在示例应用程序中,这个接口是 EJB 的远程接口,但是用 java.rmi.Remote 替换了父接口 javax.ejb.EJBObject,并 删除了调用者名称参数。

在实现 Web 服务的端点接口之后,就可以生成 WSDL了。下一节描述这个过程 。

从端点接口生成 WSDL

当前,Geronimo 应用服务器没有提供生成 WSDL 文档的标准工具集。但是, Sun 站点上的 J2EE 1.4 工具可以满足我们的需要。用于生成各种 Web 服务相关 工件的工具称为 wscompile,位于 Sun J2EE 发行版的 bin 子目录中。

要生成 WSDL 文档,应该为 wscompile 创建一个配置文件。清单 1 显示了这 个配置文件:

清单 1. wscompile 工具的配置文件

      

可以看出这个文件的结构很简单。它包含名称空间、包和服务端点接口引用的 声明。清单 2 显示了 wscompile 的调用字符串:

清单 2. 调用 wscompile

%SUN_J2EE_HOME%/bin/wscompile -classpath  ;%GERONIMO_HOME%/reposiTory/geronimo-spec/jars/geronimo-spec-j2ee-1.4-rc4.jar -gen:server - f:documentliteral config.xml

清单 2 中的 SUN_J2EE_HOME 是 Sun J2EE SDK 的主目录。APP_CLASSES 是指 定应用程序类(包括端点接口类)的目录。GERONIMO_HOME 是 Geronimo 的主目 录。注意,这个工具不只生成 WSDL,还生成几个支持类。

下一步是更新生成的 WSDL,使元素的名称在业务上下文中更容易理解。 wscompile 没有保留方法参数名,而是将它们转换为 long_2(参数类型加参数位 置)这样的名称,这将 for? 声明为方法的第二个参数,类型为 long。例如, performTransfer 操作的第二个参数可以重新命名为 amount。

接下来,确保所有消息都正好有一个部分。对于没有返回值的方法, wscompile 生成没有部分的消息。这个错误需要纠正。为了纠正这个错误,必须 声明一个包含空序列的 XML 元素,并用这个元素将一个部分添加到消息中。清单 3 演示了如何声明这样的 XML 元素:

清单 3. XSD 响应类型

      

下面是来自消息声明的片段:

清单 4. WSDL 消息

  

另外一种办法是从头开发 WSDL 文档。注意,Eclipse WTP 项目包含一个方便 的 WSDL 文档编辑器。

创建 JAX-RPC 映射

在生成 WSDL 之后,需要为方法参数创建 JAX-RPC 映射文件和值类,然后再 创建返回值。它们可以用前面提到的 wscompile 工具生成。

这种情况的 wscompile 配置见下面的 清单 5:

清单 5. wscompile 的配置

调用行如下:

清单 6. 调用 wscompile

%SUN_J2EE_HOME%/bin/wscompile -s src-gen -keep - mappingmapping.xml -classpath  -gen:client - f:documentliteralconfig.xml

这个工具的类路径与生成 WSDL 时一样。src-gen 是应该放置 JAX-RPC bean 源类的目录。注意,需要在生成 WSDL 之前创建这个目录。最好将它与应用程序 源目录分开,因为可能已经存在一些值类,wscompile 会覆盖它们。

并不是生成的所有文件都是必要的 —— 只需要缺失的 bean 的源代码。例如 ,在这个应用程序中,不需要 Account JavaBean 的源代码,因为它已经存在了 。针对不同序列化器的其他源代码也是不需要的,因为它们是 Sun J2EE 实现所 特有的。

wscompile 生成的 JAX-RPC 需要一些后期手工处理。首先,所有 wsdl- message-part-name 元素的值为 parameters。必须将它们重新命名以匹配来自部 分元素序列的对应元素名(封装的文档/字面格式的每个部分有具有复杂类型的元 素,等于元素序列)。

例如,清单 7 显示 XSD 类型:

清单 7. 显示 XSD 类型的 WSDL 片段

         

清单 8 显示消息部分中方法参数的映射:

清单 8. 方法参数的 JAX-RPC 映射

  0  java.lang.String         wsdlMsgNS:BusinessLogicEndpoint_registerUser      username   IN 

注意,文档/包装样式中的 wsdl-message-part-name 提供了元素名,而不是 消息部分本身的名称。

另一个问题是,wscompile 为返回类型是 void 的方法的返回值生成 JAX-RPC 映射(在 wsdl-return-value-mapping 元素中描述)。这些 wsdl-return- value-mapping 元素应该删除(否则在部署期间会抛出 NullPointerException) 。正确的行为在 Web services for J2EE, Version 1.0 规范中还不明确(单向 方式在这里不适合,因为调用可能失败,所以结果对于客户机很重要)。

部署 Web 服务

在下一步中,应该开发 webservices.xml 部署描述符。它将 WSDL、JAX-RPC 映射、处理程序和后端实现 bean 结合在一起。

为了演示 Web 服务处理程序的使用,我们实现了 WS-Security 的一部分功能 。因为处理程序在方法级授权之后执行,所以处理程序不能直接用于身份验证( 例如,这个业务逻辑 bean 无法公开为通过定制的处理程序执行身份验证的 Web 服务)。所以,在这个例子中,Web 服务代表外观,后端 bean 不要求授权。在 执行时,这个 bean 获得安全处理程序捕获的凭证,执行手工身份验证,并以经 过身份验证的客户机的身份调用 BusinessLogic EJB 方法。

服务器端处理程序在 webservices.xml 中指定。这个处理程序是一个实现 javax.xml.rpc.handler.Handler 接口的类。这个处理程序类的实例用于过滤所 有到达的请求、发出的响应和错误。

客户端处理程序在 web.xml 部署描述符中的服务引用中指定。

服务器处理程序 WSSecurityServerHandler 被开发成示例应用程序的一部分 ,它从到达的 SOAP 请求中提取用户名和密码,并将它们放到线程本地变量中。 这是目前将数据传输到 Web 服务后端 servlet 的惟一一种可靠的方式。Web 服 务后端 servlet 使用这些凭证进行身份验证,并使用 Geronimo 特定的身份验证 代码以经过身份验证的主体的身份调用 BusinessLogic EJB [因为只使用 Java Authentication and Authorization Service(JAAS)身份验证是不够的]。

清单 9 中的片段展示如何从安全处理程序接收主体的凭证,并以这个主体的 身份调用 EJB 方法:

清单 9. 作为某个安全主体调用业务逻辑

// username and password are obtained from the  security handlerLoginContext ctx = createLoginContext(username, password);ctx.login();try {   Set set = ctx.getSubject().getPrincipals(     org.apache.geronimo.security.IdentificationPrincipal.class);   IdentificationPrincipal idp = (IdentificationPrincipal)  set.iteraTor().next();   Subject subject =     org.apache.geronimo.security.ContextManager.getRegisteredSubject (idp.getId());   org.apache.geronimo.security.ContextManager.setCurrentCaller (subject);   return (Order[])Subject.doAs(subject, new  PrivilegedExceptionAction() {     public Object run() throws Exception {       BusinessLogic logic = BusinessLogicUtil.getHome ().create();       return logic.geTorders();     }    });} finally {   ctx.logout();}

这个片段不能转移到处理程序代码中,因为业务方法(在这个例子中是 geTorders)应该以另一个主体的身份运行(doAs 调用),而处理程序在调用服 务方法之前执行。

清单 10 展示了为这个应用程序开发的示例 Web 服务部署描述符:

清单 10. Web 服务部署描述符

     BusinessLogic   WEB-INF/BusinessLogic.wsdl   WEB-INF/jaxrpc-mapping.xml       BusinessLogicEndpointPort         ns:BusinessLogicEndpointPort             com.ibm.workdev.v1.interfaces.BusinessLogicEndpoint             BusinessLogicServiceServlet             ServerSecurityHandler           com.ibm.workdev.v1.web.wssec.WSSecurityServerHandler                wssec:Security             

部署 Web 服务客户机存根

部署 Web 服务客户机存根很简单明了。执行以下步骤来准备所需的部署描述 符和代码:

通过 URL http://localhost:8080/workdev/service?WSDL 获得 WSDL。

开发端点接口。

用 JAX-RPC 映射将 WSDL 类型映射到 Java 类型。

在部署描述符中配置 Web 服务引用。

第 2 步和第 3 步已经在上面描述过了。它们几乎与开发 Web 服务本身时的 过程一样。差异是在第 3 步中为 wscompile 工具设置 gen:client 选项,而不 是 gen:server(这个选项让 wscompile 工具生成服务接口和其他工件)。实际 上,JAX-RPC 映射和 bean 可以取自 Web 服务实现。只需要一个额外的工件,即 服务接口(它扩展 javax.xml.rpc.Service)。

服务引用放在 web.xml 中(注意,web.xml 的规范版本应该是 2.4)。清单 11 所示的片段是取自 Funds Transfer 应用程序的例子:

清单 11. 在 web.xml 部署描述符中引用 Web 服务

  service/BusinessLogicService  com.ibm.workdev.v1.web.BusinessLogicService  WEB-INF/BusinessLogic.wsdl  WEB-INF/jaxrpc-mapping.xml     servicens:BusinessLogic        ClientSecurityHandler   com.ibm.workdev.v1.web.wssec.WSSecurityClientHandler       wssec:Security    

现在已经开发了 Web 服务部署描述符,可以通过 Java Naming and DirecTory Interface(JNDI)获取 Web 服务实例了。清单 12 给出一个例子:

清单 12. 调用 Web 服务

InitialContext ctx = new  InitialContext();BusinessLogicService service =   (BusinessLogicService) ctx.lookup ("java:comp/env/service/BusinessLogicService");BusinessLogicEndpoint endpoint =  service.getBusinessLogicEndpointPort();// Invoke methods on  the endpoint interface...

在 Funds Transfer 应用程序 中,有一个调度器 servlet(WebServiceClientServlet),它与 JavaServer Pages™(JSP)一起提供一个调用 Web 服务方法的示例接口。

为什 么不使用 Eclipse WTP?

到撰写本文时,Eclipse Foundation 已经发布 了 WebTools Project 0.7,这个版本只为 Apache Geronimo 和 Web 服务提供了 最低限度的支持。尽管这个工具很有发展潜力,但是它目前缺少一些重要的特性 。

缺少的一种特性是将 Enterprise Application ARchive(EAR)文件部 署到 Geronimo 的能力。WTP 0.7 只能部署模块,比如 Web、EJB 等等。不幸的 是,本文描述的应用程序需要这种功能,因为 J2EE 应用程序部署描述符(EAR 描述符)包含重要的信息。部署所有其他模块需要这些信息,比如数据库配置、 Java Messaging Services(JMS)配置和安全配置。因此,WTP 工具 Web 服务生 成向导无法正确地生成服务,本文中这个应用程序的开发无法利用这种向导。

在 Geronimo 早期版本中遇到的另一个问题在 WTP 中也存在 —— 向导对于 Web 服务只支持 Axis 运行时。这导致创建与 J2EE 不兼容的 Web 服务,并在项目源代码中生成许多文件。另外,这些向导不支持为 服务和 Web 服务客户机指定 SOAP 处理程序。这导致手工编辑处理程序,这很费 事儿。

开发 Web 服务及其客户机时,更好的办法是更充分地支持 JSR 109 规范。当前,WTP 还没有完整地支持这个规范,因此限制了 Web 服务、Web 服务客户机及其处理程序在 Project Explorer 树中的表现;所以只能查看这些 信息,不能编辑。如果 WTP 提供丰富的编辑器和 Web 服务部署描述符(比如 webservices.xml、webservicesclient.xml 和 JAX RPC 映射描述符),也可能 会有帮助。

结束语

本文描述了如何使用 Geronimo 应用服务器提 供的 Web 服务功能来构建支持 Web 服务的应用程序。它说明了这种应用服务器 依赖于 J2EE 1.4 规范,为构建 Web 服务及其客户机提供了许多功能。

值得注意的是,尽管到撰写本文时 Geronimo 应用服务器还没有提供正式发布的 开发工具集,但是 Eclipse WTP 项目已经开始开发这些工具了。

总之, 这种应用服务器已经展现出对 J2EE 标准健壮的支持,以后一定会在中小型企业 IT 项目中占有一席之地。

曾经拥有的不要忘记,难以得到的更要珍惜,

在ApacheGeronimo应用程序中实现和部署Web服务

相关文章:

你感兴趣的文章:

标签云: