IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope:Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  SOA and Web services | WebSphere  >

使用 WAS V6.1 SOA Feature Pack 开发 SCA 应用(下)

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


方 伟 (weifang@cn.ibm.com), 软件工程师 , IBM China SOA Design Center
漆 池 (qichi@cn.ibm.com), 软件工程师, IBM中国软件开发实验室 - SOA Design Center
李 旭 (christli@cn.ibm.com), 软件工程师, IBM中国软件开发实验室 - SOA Design Center
王 征 (wangzzh@cn.ibm.com), 软件工程师, IBM中国软件开发实验室 - SOA Design Center

2008 年 3 月 06 日

本文的 上半部分 介绍了 WAS(Websphere Application Server)V6.1 的 SOA Feature Pack 的一些概念和功能,并且通过一个实例描述怎样利用这个 Feature Pack 进行 SCA 开发。本文为文章的下半部分,继续向您介绍了一个实例来描述如何进行 SCA 开发。读者通过本文既可以对 SOA Feature Pack 这个产品组件有一定的了解,也可以对 SCA 加深理解,体会到 SCA 架构在开发 SOA 应用中的特点和优势。本文的目标读者技术级别为初级。

SCA 集成应用的开发

下面我们通过另外一个示例来说明 SOA Feature Pack 的其他重要功能点,并且简单演示如何利用 SCA 开发企业集成应用。一个银行系统提供给客户的服务可以包括帐户管理,存取款,转账,贷款等服务。这些服务有的是已有系统中存在的,有的是需要开发新系统实现的,在 SOA 应用中往往需要对这些异构系统进行整合。运用 SCA 构架体系为这种类型的业务整合提供了强大的支持和良好的封装性,并使开发简单便利。

示例概述

在我们的示例中,提供四个银行账户服务:存款、查询余额、取款、转账。其中存款、查询余额以及取款由 EJB 实现的已有系统提供,转账为新开发的服务,以 Web Service 的形式体现。下面先看 EJB 提供的功能:

清单 1 AccountEJB 的 Remote 接口

package ejbs;

/**
 * Remote interface for Enterprise Bean: AccountEJB
 */
public interface AccountEJB extends javax.ejb.EJBObject {

	/**
 * @param accountId, ID of the customer's bank account
	 * @return the balance of the customer's account
	 * @throws java.rmi.RemoteException
	 */
	public double getBalance(String accountId) throws java.rmi.RemoteException;

	/**
	 * @param accountId, ID of the customer's bank account
	 * @param amount, how much does the customer want to deposit
	 * @throws java.rmi.RemoteException
	 */
	public void deposit(String accountId, double amount)
			throws java.rmi.RemoteException;

	/**
	 * @param accountId, ID of the customer's bank account
 * @param amount, how much does the customer want to withdraw
	 * @throws java.rmi.RemoteException
	 */
	public void withdraw(String accountId, double amount)
			throws java.rmi.RemoteException;
}

AccountEJB 提供存款、查询余额以及取款的功能,其 Remote 接口定义如清单 1 所示。getBalance 为查询余额操作,它接受银行受帐户 ID,返回帐户余额;deposit 为存款操作,它接受帐户 ID 以及存款额度;withdraw 为取款操作,它接受帐户 ID 以及取款额度。

下面定义转账服务的 Web Service,首先为转账操作的接受的参数信息定义 XML Shcema – BankService.xsd,该 Schema 如清单 2 所示 AccountTransfer 为转账操作参数类型,它是一个 Complex Type,包含三个属性,分别为来源帐户,目的帐户,以及转账额度。有了 Schema 后接着定义转账操作的 WSDL – BankService.wsdl,如清单 3 所示(未列出 service 以及 port),该 WSDL 定义了一个名为 BankService 的 portType,包含一个操作 transfer,它接受之前定义的 AccountTransfer 作为参数,返回 boolean 以表示转账是否成功。该 WSDL 以 document-literal-wrapper 方式定义。

清单 2 转账参数 Schema

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
	xmlns:tns="http://demo.sca/BankService" elementFormDefault="qualified"
	targetNamespace="http://demo.sca/BankService">
	<complexType name="AccountTransfer">
		<sequence>
			<element name="fromAccount" type="string" />
			<element name="toAccount" type="string" />
			<element name="amount" type="double" />
		</sequence>
	</complexType>
</schema>

清单 3 转账操作 WSDL

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
	xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
	xmlns:tns="http://demo.sca/BankService"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="BankService"
	targetNamespace="http://demo.sca/BankService">
	<wsdl:types>
		<xsd:schema targetNamespace="http://demo.sca/BankService"
			xmlns:xsd="http://www.w3.org/2001/XMLSchema">
			<xsd:include schemaLocation="BankService.xsd" />
			<xsd:element name="transfer">
				<xsd:complexType>
					<xsd:sequence>
						<xsd:element name="accountTransfer"
							type="tns:AccountTransfer" />
					</xsd:sequence>
				</xsd:complexType>
			</xsd:element>
			<xsd:element name="transferResponse">
				<xsd:complexType>
					<xsd:sequence>
						<xsd:element name="success" type="xsd:boolean" />
					</xsd:sequence>
				</xsd:complexType>
			</xsd:element>
		</xsd:schema>
	</wsdl:types>
	<wsdl:message name="transferRequest">
		<wsdl:part element="tns:transfer" name="parameters" />
	</wsdl:message>
	<wsdl:message name="transferResponse">
		<wsdl:part element="tns:transferResponse" name="parameters" />
	</wsdl:message>
	<wsdl:portType name="BankService">
		<wsdl:operation name="transfer">
<wsdl:input message="tns:transferRequest" />
			<wsdl:output message="tns:transferResponse" />
		</wsdl:operation>
	</wsdl:portType>			
</wsdl:definitions>

至此,我们已经有了一个 EJB 提供的服务以及一个 Web Service 提供的服务,下面描述如何建立一个 SCA 应用来集成它们。

Java 生成

注意到在生成 Web Service 的时候,定义了一个 XSD 的 Complex Type:AccountTransfer 作为 Web Service 操作的参数,在 SCA 实现的时候,需要以 Java 的方式创建并且使用这个类型,因此需要一个由 XSD 到 Java 的转换。如文章上半部分中所述,这个功能是由 SOA Feature Pack 的 XSD2Java 工具提供的。此外在创建 SCA 实现的时候,也需要有一个 Java 接口来表示 WSDL 里定义的 portType,因此需要一个 WSDL 到 Java 的转换,这个功能由 WSDL2Java 工具提供。下面演示怎样在 RSA 中使用这两个工具:

  • 在 Project Explorer 视图中右击 BankService.xsd,选择 Run As -> Run...,弹出运行配置对话框。
  • 在左侧的运行类型树中,右击“Java Application”,选择 New,进入编辑 Java 运行启动项的配置界面。
  • 在“Main”的配置页中(如图 1 所示),在 Main class 中搜索出 org.apache.tuscany.sdo.generate.XSD2JavaGenerator 类,该类是 XSD2Java 工具的入口。注意必须勾选“Include libraries when searching for a main class”的选项。(在工程建立时必须配好 SOA Feature Pack 的 classpath)。

图 1 XSD2Java 启动项配置

  • 在 Arguments 配置页中,“Program arguments”处填入 XSD2Java 工具的运行参数,如图 2 所示。其中 -targetDirectory 表示生成的 Java 类放在哪个源目录中,${resource_loc} 是 XSD 文件的位置,这里取右击时的目标文件位置。

图 2 XSD2Java 启动项配置

  • 配置好启动项后,点击“Run”,则会在 src/main/java 目录中生成 Java 类,其中包含:
    • AccountTransfer 接口,它是 JavaBean 形式的 SDO 接口,用来表示 BankService.xsd 中定义的类型。
    • ServiceFactory 工厂类接口,它是 BankService.xsd 中定义的所有复杂类型的 SDO 创建工厂,其命名由 XSD 中的 namespace 决定。
    • AccountTransfer 以及 ServiceFactory 的实现类。

至此,对 BankService.xsd 的 Java 生成工作已经完成。

  • 对 BankService.wsdl 也需要运行 XSD2Java 工具,因为在对 BankService 采用的是 document-literal-wrapper 方式的定义,其 wsdl 中包含内嵌的 XSD 类型 transfer 以及 transferResponse,需要将它们生成 Java 类。运行参数与处理 BankService.xsd 时类似。
  • 对 BankService.wsdl 进行 WSDL2Java 的操作以生成 SCA 组件中所需的接口。操作的流程与运行 XSD2Java 类似,不过在“Main”的配置页中,“Main class”处应搜索 org.apache.tuscany.tools.wsdl2java.generate.WSDL2JavaGenerator 类。清单 4 列出了生成出的 Java 接口。

清单 4 BankService.wsdl 生成的 Java 接口

/**
 * BankService.java
 *
 * This file was auto-generated from WSDL
 * by the SOA Feature Pack WSDL to Java tool
 */

package sca.demo.bankservice;

import org.osoa.sca.annotations.Remotable;

/*
 * BankService java interface
 */

@Remotable
public interface BankService {

	/**
	 * Auto generated method signatures
	 */

	public boolean transfer(sca.demo.bank.service.AccountTransfer transfer);

}

至此,Java 生成的工作已经完成,下面可以利用生成的 Java 类进行 SCA 组件的开发。

SCA 组件接口与实现

首先为需要建立的 SCA Component 定义接口,该接口集成了 AccountEJB 的功能以及 BankService 服务的功能,清单 5 为该接口的代码,注意需要使用 @Remotable 将接口声明成远程 SCA 接口。

清单 5 SCA 组件接口

package sca.demo.banksca;

@Remotable
public interface BankClient {
public double getBalance(String accountId);

	public void deposit(String accountId, double amount);

	public void withdraw(String accountId, double amount);

	public boolean transfer(sca.demo.bank.service.AccountTransfer transfer);
}

接着为此接口创建实现类,该实现类即我们所需要创建的 SCA Component 的实现,实现类的代码如清单 6 所示,此实现类中有以下需要注意的地方:

  • 需要将 AccountEJB 的 Remote 接口导入到此 SCA 应用中,并且在实现类中建立此接口的 Reference
  • 需要为 WSDL2Java 工具生成的接口 BankService 创建 Reference。
  • 在实现 SCA 组件的业务功能时,分别调用 EJB 接口和 WSDL 接口的相应方法实现,并且进行一定的异常处理。

清单 6 SCA 组件实现

package sca.demo.banksca;

import java.rmi.RemoteException;

import org.osoa.sca.annotations.Reference;
import org.osoa.sca.annotations.Service;

import sca.demo.bank.service.AccountTransfer;
import sca.demo.bankservice.BankService;
import ejbs.AccountEJB;

@Service(BankClient.class)
public class BankClientImpl implements BankClient {

	public AccountEJB ejbReference;

	public BankService wsReference;

	public AccountEJB getEjbReference() {
		return ejbReference;
	}

	@Reference
	public void setEjbReference(AccountEJB ejbReference) {
		this.ejbReference = ejbReference;
	}

	public BankService getWsReference() {
		return wsReference;
	}

	@Reference
	public void setWsReference(BankService wsReference) {
		this.wsReference = wsReference;
	}


public void deposit(String accountId, double amount) {
		try {
			ejbReference.deposit(accountId, amount);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}

	public double getBalance(String accountId) {
		try {
			return ejbReference.getBalance(accountId);
		} catch (RemoteException e) {
			e.printStackTrace();
			return 0;
		}
	}

	public boolean transfer(AccountTransfer transfer) {
		return wsReference.transfer(transfer);
	}

	public void withdraw(String accountId, double amount) {
		try {
			ejbReference.withdraw(accountId, amount);
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}
}

SCA 组件部署

清单 7 给出了我们所需要创建的 SCA 组件的 Composite 定义,其中,我们创建了名为 BankDemoComponent 的 SCA component,并且使用了“SCA 组件接口与实现”节中给出的 Java 实现作为其 implementation,为 BankDemoComponent 创建了两个 Reference:采用 EJB Binding 的 ejbReference 以及采用 Web Service Binding 的 wsReference。其中有以下几点需要注意的地方:

  • 由于在 SCA 组件中定义了 SDO,并且以 JavaBean 的形式使用,因此在 Composite 定义中需要声明 SDO 的工厂类。import.sdo 元素即为此声明的方式,它的名称空间为 http://tuscany.apache.org/xmlns/sca/databinding/sdo/1.0。factory 属性用来指定工厂类实现的全名。
  • 在 EJB binding 中,接入点的描述为 corbaname:iiop:localhost:2809/NameServiceServerRoot#ejb/ejbs/AccountEJBHome,其中,localhost 为 EJB 所在的 J2EE 服务器地址,2809 为服务器的远程调用接口,ejb/ejbs/AccountEJBHome 为 EJB 的 JNDI 名称。
  • 对于 Web Service Binding 的 Reference,既可以用 WSDL 形式的 interface 声明,也可以用 Java 形式,由于本例中使用 WSDL2Java 生成了对应的 Java 接口,该接口即可以用来声明此 Reference。

清单 7 SCA 组件 Composite 定义

<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
	xmlns:system="http://tuscany.apache.org/xmlns/system/1.0-SNAPSHOT"
	xmlns:dbsdo="http://tuscany.apache.org/xmlns/sca/databinding/sdo/1.0"
name="BankDemoClient">
	<dbsdo:import.sdo factory="sca.demo.bank.service.ServiceFactory" />

	<component name="BankDemoComponent">
		<implementation.java class="sca.demo.banksca.BankClientImpl" />

		<reference name="ejbReference">
			<interface.java interface="ejbs.AccountEJB" />
			<binding.ejb
				uri="corbaname:iiop:localhost:2809/NameServiceServerRoot#ejb/ejbs/AccountEJBHome" />
		</reference>
		<reference name="wsReference">
			<interface.java
				interface="sca.demo.bankservice.BankService" />
			<binding.ws
				wsdlElement="http://demo.sca/BankService#wsdl.port(BankService/BankServiceSOAP)" />
		</reference>
	</component>
</composite>

最后我们为建立的 SCA 组件创建演示界面,清单 8 给出了演示界面中,调用 SCA 组件的代码,其中创建 SCA component 的过程与第 3 章中的示例类似。从此代码中可以看出 SCA 组件的使用方式,为非常简单的 Java 调用,SCA 运行环境会自动将 Java 调用转换成具体的 EJB 客户端调用或者 Web Service 客户端调用,从这里可以看到 SCA 架构良好的封装性。

清单 8 演示界面部分代码

CompositeContext compositeContext = CurrentCompositeContext.getContext();
BankClient bankClient = (BankClient) compositeContext.locateService(BankClient.class, 
   "BankDemoComponent");

//deposit operation
bankClient.deposit(accountId, amount);

//getBalance operation
double balance = bankClient.getBalance(accountId);

//withdraw operation
bankClient.withdraw(accountId, amount);

//transfer operation
AccountTransfer accountTransfer = ServiceFactory.INSTANCE.createAccountTransfer();
accountTransfer.setFromAccount(fromAccount);
accountTransfer.setToAccount(toAccount);
accountTransfer.setAmount(amount);
bankClient.transfer(accountTransfer);

将创建出的描述文件以及源文件按照图 3 的目录结构打成 war 包,然后按照文章上半部分中所描述的方法进行部署,在浏览器中输入示例 JSP 页面的地址,就可以看到如图 4 的运行结果。


图 3 SCA 组件部署目录结构


图 4 运行结果

示例总结

通过上面了示例演示了用 SOA Feature Pack 进行 SCA 集成应用开发的流程和方法,包括使用 XSD2Java 以及 WSDL2Java 生成 Java 类代码,EJB Binding 和 Web Service Binding 的声明和实现方式,以及 SCA 组件的开发和部署。





回页首


总结

SCA 规范是一种新的应用架构和编程模型,在 SOA 开发中具有强大的优势和生命力,对 SOA 的发展有着重要的意义。SOA Feature Pack 为在 WAS 上开发 SCA 应用提供了运行平台和工具。本文首先介绍了 SCA 的基本概念,接着描述了 SOA Feature Pack 的概况和新功能,然后通过两个具体的示例展示了如何使用 SOA Feature Pack 进行 SCA 开发。内容包括 Asset 的创建,Business Level Application 的创建,SCA 回调方式组件的开发,Web Service Binding 和 EJB Binding 的开发,以及 SCA 组件的部署,管理等。读者通过本文可以对 SCA 有较为具体的认识,同时对在 WAS 上进行 SCA 开发有较为形象的概念。



参考资料

学习

获得产品和技术
  • 使用 IBM 试用软件 开发您的下一个项目,可下载或索取 DVD 光盘。


讨论


作者简介

方伟 : CDL SOA 设计中心软件工程师,从事 SOA 测试工具的开发


漆池,IBM CDL SOA 设计中心软件工程师,从事 SOA 测试工具的开发工作。


李旭,IBM CDL SOA 设计中心软件工程师,从事 SOA 测试工具的开发工作。


王征,IBM CDL SOA 设计中心软件工程师,从事 SOA 测试工具的开发工作。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?




回页首


IBM、IBM 徽标和 WebSphere 是 IBM 在美国和 / 或其他国家 / 地区的注册商标。 Java 和所有基于 Java 的商标都是 Sun Microsystems, Inc. 在美国和 / 或其他国家 / 地区的商标。 其他公司、产品或服务的名称可能是其他公司的商标或服务标志。

IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款