UML软件工程组织

利用SOA简化业务流程----使用 WebLogic Workshop 8.1 快速构建业务流程
作者:David Hritz  来源:网络

在 BEA WebLogic Workshop 8.1 中,构建面向服务的架构 (SOA) 目前已成为一项简单的任务。BEA 提供了一种机制,用于可视化地创建复杂的业务流程和服务。在下面的内容中,我将指导您一步一步地创建抵押代理公司的流程。希望本文能让您深入了解如何利用 WebLogic Workshop 的强大功能构建面向服务的架构(SOA)。

我们假定已经为流程生成了任意数量的子系统,用于访问支付流程,支付流程根据贷款数目和条款计算每月应缴纳的费用。代理公司通常与大量的信用机构打交道,以便完成贷款。在我们的例子中,代理公司将与国家银行和地方银行打交道。这两家机构都开通了 Web 服务,我们可以利用该 Web 服务获得当前的贷款利率等信息。我们的业务流程将把这些服务合并到自己的逻辑中,从而尽可能为用户提供最新的信息。

开始

在开始构建业务流程之前,需要构建业务流程所依赖的 Web 服务。我们的服务不仅应能够返回银行当前的利率,还应能够返回银行的名称。出于本例目的,将通过从静态定义的利率表中随机选择值的方式来计算当前利率。下面的步骤将指导您完成在 Workshop 中创建所需的应用程序、项目和服务的步骤。

首先,需要创建一个空的应用程序:

· 选择File > New > Application…,出现New Application对话框。

· 选择Empty Application,并将其命名为 Brokerage。

· 单击Create。

下面创建 Web 服务项目:

· 右键单击 Brokerage 文件夹。

· 选择New > Project…,出现New Project对话框。

· 选择Web Service Project,并将其命名为 WebServices。

· 单击Create。

创建国家银行服务:

· 右键单击 WebService 文件夹。

· 选择New > Folder,并将文件夹命名为 nationalbank。

· 右键单击 nationalbank 文件夹。

· 选择New > Web Service,出现New File对话框。

· 将该 Web 服务命名为 NationalBankService。

· 单击Create。编辑窗格中将显示新创建的服务。

· 右键单击编辑窗格中的服务,选择Add Method。

· 将方法命名为 getCurrentRate。

· 单击Source View选项卡。

· 修改该 Web 服务,使其与 清单1 一致。

· 选择File > Save

清单1. 抵押代理公司创建国家银行Web服务的代码

package nationalbank;

public class NationalBankService

implements com.bea.jws.WebService

{

static final long

serialVersionUID = 1L;

static final double[] rates =

{.0625 , .0525, .06375, .055,

.05375, .05625, .05875, .06,

.0575, .06125};

public static class Quote

{

public double rate;

public String name;

public Quote() {}

public Quote (String name,

double rate)

{

this.rate = rate;

this.name = name;

}

}

/**

* @common:operation

*/

public Quote getCurrentRate()

{

String milliSecs =

String.valueOf(

System.currentTimeMillis());

double rate = rates[

Integer.parseInt(

String.valueOf(

milliSecs.charAt(

milliSecs.length()-1)))];

return new Quote(

"National Bank", rate);

}

}

窗体底端

如前所述,Web 服务随机地从静态定义的两个利率表中获得利率。由于我们的服务还需要返回银行的名称,所以我们需要创建一个能够同时存储这两个值的对象。我们已经知道,getCurrentRate() 方法能够创建并返回 Quote 对象。Local Bank 服务起到相同的作用,二者的不同之处在于,我们将更改列表中声明利率的顺序。这样做可以使得在每次执行流程时,能够提供不同结果的更好机会。这里没有必要再次执行构建 Local Bank 服务所需的所有步骤,只需复制 National Bank 服务即可。下面的操作步骤将指导您完成这一任务。

复制 National Bank 服务:

· 右键单击 WebService 文件夹。

· 选择New > Folder,将文件夹命名为 localbank。

· 右键单击 NationalBankService ,并选择Duplicate。

· 将新创建的 NationalBankService1 拖放到 localbank 目录。

· 将 NationalBankService1 重命名为 LocalBankService。

· 更改利率表中定义利率的顺序。

· 将返回的名称更改为Local Bank。

· 执行File > Save。

设置业务流程所使用的服务的最后一步是,为每个服务创建一个 WSDL 文件。通过单键右击每个服务并选择Generate WSDL File,可以轻松完成这一操作。

构建完服务之后,有一项最后的任务需要在构建业务流程之前完成。在本例中,作为对客户的回应,我们的业务流程应向客户返回一个 XMLBean。所以在开始创建业务流程之前,需要通过导入该对象的架构来创建该对象。

 导入架构文件

下一步是创建 Schema 项目,以及创建将用于向客户返回信息的 XMLBean 对象。这里实际上没有必要使用 XMLBean,使用 JavaBean 就可以完全满足要求。但越来越多的服务和过程都开始以 XML 为中心,所以我感觉有必要让您领略一下 XMLBean 技术。XML 是以文本形式表示数据的最佳方法,也是在 Internet 上使用的选择的消息格式。您很快就会看到,XMLBean API 在访问 XML 数据方面为开发人员提供了更多的控制功能。有了 XMLBean 的帮助,可以使用 XML 架构生成表示 XML 的 Java 对象,还可以在不泄漏初始 XML 文档的情况下为您提供 SAX 和 DOM 类型的导航和操作功能。

在进行这一步骤之前,应按照创建 Web 服务项目的方法创建另一个项目。在创建该项目时,请确保选择 Schema Project 选项,并将该项目命名为 Schemas。新建项目将显示在 Application 选项卡中。

有了 Schema 项目,我们就可以仅导入 XML 架构,Schema 项目能够根据此架构自动生成 XMLBean Factory 和 XMLBean 对象。您也可以在该项目中创建具有相同功能的自己的 XML 架构。在本例中,我们将从 清单 2 中导入该架构。

清单 2. Schema 项目允许我们导入 XML 架构,Schema 项目能够根据此架构自动生成 XMLBean Factory 和 XMLBean 对象。

<?xml version="1.0"?>
<xsd:schema targetNamespace=
"http://nws.com/brokerage" xmlns:
xsd="http://www.w3.org/ 2001/XMLSchema">
<xsd:element name="quote">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="lender" type="xsd:string"/>
<xsd:element name="loanAmount" type="xsd:double"/>
<xsd:element name="term" type="xsd:int"/>
<xsd:element name="rate" type="xsd:double"/>
<xsd:element name="payment" type="xsd:double"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>

导入 Schema:

· 右键单击 Schema 项目并选择 Import。

· 出现 Import Files 对话框。

· 定位至在清单 2 中存储的 XML Schema 所在的位置。

· 选择 Import。

· 请注意 Schema 项目自动启动了构建过程。

· 构建完成之后,展开 XML Bean Classes 子文件夹,检查生成的类。

至此我们完成了所有前期工作,可以着手进行业务流程的开发。这时“应用程序”选项卡应与图 1 类似。


 图 1. 在创建抵押代理业务流程中完成了准备任务之后,Application 选项卡应该类似于此图。

开发业务流程

要开始构建业务流程,需要创建一个新项目。这里我们创建一个 Process Project ,并将其命名为BrokerageProcesses。在创建 Process Project 时,系统将在流程子文件夹下方为您创建文件名为 process.jpd 的流程文件。我们将对该文件进行修改;双击该文件,以在 Edit 窗格中打开该文件(参见 图 2)。


 图2. 在创建 Process Project 时,系统将在流程子文件夹下方为您创建名为 process.jpd 的流程文件。我们将对该文件进行修改。

下面我们看一下创建该业务流程必须执行的每个步骤。首先我们希望客户的请求能够启动该流程。我们还希望获得每个银行的当前利率的信息,这样我们就不必为了等待我们的服务完成操作而保持处理状态。我们还需要对两个返回的利率值进行比较,以确定收费较低的银行,并根据返回的利率值计算每月应缴纳的费用。最后,我们将利用计算结果构造 XMLBean,并将其返回给客户。

第一步是设置客户请求。Workshop 提供了多种启动业务流程的方法。我们希望由客户的请求来启动业务流程。侧栏“请求和响应”能够指导您完成设置 Client Request 节点和客户响应的一系列步骤。

请求和响应

下面是设置Client Request 和Client Response节点所必需的步骤。要设置客户请求:

· 双击Starting Event节点,允许您选择该流程启动的方式。在本例中,流程是Invoked via a Client Request 。选择此选项,单击OK。

· 注意Starting Event 更改为:


 将此事件重命名为 Request Quote。

· 双击 Request Quote 节点。

· 在 General Settings 选项卡上,将Method Name 更改为requestQuote。

· 我们知道客户将输入贷款数目和期限。使用Add… 按钮添加 requestQuote方法的这些参数类型。

· 单击Add…

· 选择Java作为参数类型。

· 在Java Types下,选择double。

· 将其命名为loanAmount,参见图 3。

· 然后为贷款期限添加参数,这次选择int,名称为term。

· 单击Receive Data 选项卡。

· 注意它已经设置为接收double和int 数据类型。

· 在 Select Variables 下赋值,选择Create new variable…

· 分别输入 loanAmount和term 的名称。

· 注意 loanAmount和term现在可以在Data Palette 上的 Java 变量下使用了。

· 单击 Apply。

· 单击Close。

· 选择 File > Save 保存工作。

我们现在向前跳过一些步骤来创建客户响应,因为它将创建一个我们在处理过程中需要的成员变量。以下步骤向您展示了如何设置客户响应。

要设置Client Response:

· 从 Palette拖动Client Response节点,


 将它直接放到Get Quote 节点之后。

· 将 Client Response 节点重命名为Return Quote。

· 双击 Return Quote 节点。

· 在General Settings 选项卡中,将 Method Name 更改为 returnQuote。

· 我们已经注意到流程将返回一个 XMLBean给客户机。使用 Add…来为 returnQuote方法添加这个参数类型。

· 单击 Add…

· 选择 XML 作为参数类型。

· 在 XML Types > Typed > quote.xsd下,选择quote。

· 单击 Send Data tab。

· 注意它已经设置为返回一个QuoteDocument。

· 在 Select Variables 下赋值,选择Create new variable…

· 命名变量brokerageQuote。.

· 注意 brokerageQuote现在在 Data Palette 上的XML变量下可以使用了。

· 单击 Apply。

· 单击 Close。

· 选择 File > Save 来保存工作。
 
 图 3. 遵循与创建Client Request 相同的步骤,显示屏幕应该类似于此图。

现在我们可以开始开发业务流程的主逻辑。我们需要获取每个贷款银行的当前利率,可以通过依次调用相应的服务达到这一目的,在这一过程中,没有必要等待其中的一个流程结束之后才启动另一个流程,毕竟国家银行的业务量一般要比本地银行的业务量要大,并且从我们的角度看,使一个服务在另一个服务结束之后再启动并不重要,因为这些服务之间不存在相互依赖的关系。我们可以使用 Palette 中的其他节点进行并行处理,以异步的方式调用每个 Web 服务。该节点称为 Parallel 节点,侧栏“功能强大的控件”显示了该节点的操作步骤。

功能强大的控件

我们需要从每一贷款机构获得当前利率。我们可以使用 Palette 中的节点来处理并行处理(称为 Parallel节点),并异步地执行每一Web服务调用。

为了从 Parallel节点调用服务,我们需要创建两个 Web 服务控件,一个用于国家银行,一个用于地方银行。

要创建Web 服务控件:

· 在 Data Palette的 Controls下,选择Add 。

· 选择 Web Service。

· Insert Control 对话框出现(参见 图 4)。

· 在 Step 1中,设置控件的变量名为 nationalBankControl。

· 在 Step 2中,选择Create a new Web Service control to use。

· 设置新的 JCX 名称为 NationalBankControl。

· 在 Step 3 中,浏览WebServices/nationalbank/NationalBankServiceContract.wsdl。

注意:国家银行和地方银行已经公布自己的wsdl文件,我们将使用UDDI来查找这些文件。由于我们的银行是虚构的,并且已经在本地创建,我们将使用本地文件系统中的wsdl文件。

遵循与LocalBankService相同的步骤,但这次变量名采用localBankControl ,将新的JCX命名为 LocalBankControl,并且浏览WebServices/localbank/LocalBankServiceContract.wsdl。

注意 nationalBankControl 和localBankControl 都已经添加到Data Palette。我们将在要创建的Parallel节点中使用这些控件。

要添加Parallel 节点:

· 从 Palette 拖动Parallel 节点,


 直接放至 Get Quote 节点后。

· 将Parallel节点重命名为Get Current Rates。

· 重命名最左边的分支为 Get National Rate。

· 重命名其他分支为Get Local Rate。

· 在 Data Palette 中展开nationalBankControl。

· 将getCurrentRate方法拖动到 Get Current Rates 节点的Get National Rate分支。

· 将最新创建的 getCurrentRate 节点重命名为Get National Rate 。

· 双击 Get National Rate 节点。

· 注意在 General Settings 选项卡中,nationalBankControl 和getCurrentRate方法已经选中。

· 选择Receive Data选项卡。

· 这次我们不进行变量选择或者创建,我们把返回的变量变换成一个 QuoteDocument。

· 选择 Transformation。

· 在 Step 1中,选择 Select Variable。

· 选择 Create new variable…

· 创建另一个QuoteDocument 变量,并将它命名为nationalQuote。

· 在Step 2中,选择Create Transformation。

· Transformation Editor 出现了。

· 从 Source Schema中,将rate 拖动到Target Schema rate,并命名为lender (参见 图 5)。

· 单击 File > Save 保存该变换。

· 关闭变换,返回到 Edit窗格中的 process.jpd。

· 单击 Apply。

· 单击 Close。

· 遵循与localBankControl相同的步骤。

· 将getCurrentRate方法拖动到 Get Current Rates 节点的Get Local Rate 分支。

· 将返回的变量命名为 localQuote 。

· 单击 File > Save 保存该变换。
 
 图4. Insert Control 对话框用于创建Web 服务控件。



 图 5. 创建parallel节点的步骤之一是拖动rate 到Target Schema rate ,并将之命名为lender。

窗体底端

现在,每项服务都将创建自己的 QuoteDocument。我们可以据此比较这些利率的值,以确定其中较低的值。可以利用 Palette 中的 Decision 节点完成这一操作。决策节点能够根据某些条件的计算结果执行流程相应的分支。

以下是获得最低利率的方法:

· 将 Decision 节点从 Palette 直接拖放至 Get Current Rates 节点下方。

· 将该节点重命名为 Is National Lower?

· 将 Condition 分支重命名为 Yes。

· 将 Default 分支重命名为 No。

· 双击 Yes 节点。

· 使 Schema 处于被选中状态。

· 单击 Select Variable 并选择 nationalQuote 变量。

现在应显示 QuoteDocument 节点。请继续执行下面的操作:

· 选择利率节点,Left Hand Expression 已经填写完毕。

· 选择 “<” 运算符。

· 我们希望使用 localQuote 对象中的利率节点作为 Right Hand Expression,输入 data($localQuote/rate),按 Add。

请注意,这时已经向条件列表中添加了条件,但 Right Hand Expression 被引号括起。这表示程序将尝试进行字符串比较,而不是按照我们所希望的对节点值进行比较,所以我们将在 Source View 中对此进行以下修改,以达到我们的目的:

· 单击 Apply。

· 单击 Close。

· 单击 Source View 选项卡。

· 展开 Process Language Section。

· 用 清单 3 中的更新块替换整个块。

· 单击 File > Save,保存该转换。

清单 3. Right Hand Expression 被引号括起,表示程序将尝试进行字符串比较,而不是按照我们所希望的对节点值进行比较。我们将利用下面的代码在 Source View 中对此进行修改。
/** * @jpd:process process:: *
<process name="process"> *
<clientRequest name= * "Request Quote" method= * "requestQuote"/> *
<parallel name= * "Get Current Rates"> *
<branch name="Get National * Rate"> *
<controlSend name= * "Get National Rate" * method= * "nationalBankControlGetCurrentRate"/> * </branch> *
<branch name= * "Get Local Rate"> *
<controlSend name= * "getCurrentRate" * method= * "localBankControlGetCurrentRate"/> *
</branch> * </parallel> * <decision name= * "Is National Lower?"> *
<if name="National Is Lower" * condition= * "cond_nationalQuote_1( * $nationalQuote, * $localQuote)"/> *
<default name="Local Is Lower"/> *
</decision> *
<clientCallback name= * "Return Quote" method= * "clientResponseCallbackHandler"/> *
</process>:: * @jpd:xquery prologue:: * define function * cond_nationalQuote_1( * element $nationalQuote, * element $localQuote) * returns xs:boolean { * data($nationalQuote/rate) * < data($localQuote/rate) * } * :: */

使用 清单 3 中的内容替换流程控制逻辑后,Decision 节点应该能够通过比较节点确定其架构中两个利率之中的较低的利率。因为我们已将用于响应客户的节点设置为返回 brokerageQuote 变量,所以我们希望根据所执行的决策分支将 brokerageQuote 变量设置为返回的 QuoteDocument,这要求编写少量的自定义代码。为达到这一目的,我们将使用一个 Perform 节点。Perform 节点就是一个可视的占位符,可用来向业务流程中添加我们自己的方法和逻辑。

以下是向决策树中添加 Perform 节点的方法:

· 将 Perform 节点 拖放至 Yes 分支。

· 将该 Perform 节点重命名为 Set National Quote。

· 双击 Set National Quote。

· 将方法重命名为 setNationalQuote。

· 单击 View Code。

· 在 setNationalQuote 方法中添加以下语句行:

brokerageQuote = nationalQuote;· 切换回设计视图。

· 单击 Set National Quote 节点中的 Close。

对 No 分支执行相同的操作,不同之处在于将节点重命名为 Set Local QuoteM,将方法重命名为 setLocalQuote。在新建的方法中加入以下语句行:

brokerageQuote = localQuote;现在单击 File > Save,保存所做的变换。

再往下可以做最后的计算。现在我们已经得到当前最低的利率,我们要在该利率上加上我们的佣金,使用该值计算每月应缴纳的费用。计算完成之后,就完成了构建 brokerageQuote 的工作,可以将其返回给客户。正如您可能已经推测的,要完成该业务流程,我们还需要使用另一个 Perform 节点:

· 将 Perform 节点从 Palette 直接拖放至 Is National Lower? 节点下方。

· 将该 Perform 节点重命名为 Calculate Payment。

· 双击 Calculate Payment 节点。

· 将方法重命名为 calcPayment。

· 选择 View Code。

清单4 中包含了完成此流程必需的所有计算。用 清单 4 中的 calcPayment() 方法替换此处的 calcPayment() 方法。

清单 4. 要完成业务流程,我们还需要在最低利率上添加佣金,用该值计算每月应缴纳的费用。

public void calcPayment()
throws Exception{ QuoteDocument.Quote quote = brokerageQuote.getQuote();
double rate = quote.getRate() + .005;
double monthlyRate = rate / 12;
int months = term * 12;
double payment = ((loanAmount)*(( monthlyRate*Math.pow( 1+monthlyRate, months))/(( Math.pow( 1+monthlyRate,months))-1)));
payment = (Math.round( payment * 100.00d) / 100.00d);
quote.setRate(rate);
quote.setPayment(payment);
quote.setLoanAmount(loanAmount);
quote.setTerm(term);}

您需要导入 com.nws.brokerage.QuoteDocument。可以通过将鼠标指针悬浮在QuoteDocument 上并按 Alt+Enter 组合键完成这一操作。现在切换回 Design 视图,然后单击 Calculate Payment 节点上的 Close。

现在我们已经完成了整个业务流程,这时流程应与 图 6 所示的流程类似。


 图 6. 业务流程构建完毕之后,应与该图类似。

测试业务流程

最后一步是测试业务流程。我们将使用 Workshop 提供的 Test Browser 完成这一工作。要测试业务流程,请按 Debug 工具栏中的 Start 按钮 。如果服务器没有启动,系统会提示您启动服务器。按 OK 以启动服务器。启动服务器之后,系统还会提示您部署应用程序,选择 OK 可以部署程序。

部署应用程序之后,系统将打开 Workshop Test Browser(如 图 7 所示)。最左边的一列是Message Log,日志中包含了流程从开始到结束的每一个步骤的有关信息。右侧的窗格是一个窗体,可以在其中输入调用流程所必需的数据。


 图 7. 抵押代理应用程序部署之后,将打开 Workshop 测试浏览器。

输入 loanAmount 和期限值(本例输入 100000 作为 loanAmount 值,30 作为期限值),按下 requestQuote 按钮启动流程,Message Log 将记录流程的状态。按下 Refresh 按钮数次,可以发现系统总会调用 nationalBankControl.getCurrentRate 和 localBankControl.getCurrentRate。单击其中的任意一项,系统都会显示相应服务的响应。最后您会看到 callback.returnQuote 的消息。单击此消息,系统将显示发送给客户的消息。在本例中,本地银行的利率较低。从返回的 XML 中可以清楚地看出(如图 8 所示)。


 图 8. 在本应用程序中,本地银行提供的贷款利率较低。

业务流程测试完毕后,可以将其合并到门户程序,也可以将其合并到其他业务流程中。

我们可以在这么短的时间内创建支持复杂的业务流程的功能性业务流程。BEA 提供了用于创建 SOA 的简单的机制。现在我们可以在短时间内可视化地设计和开发出复杂的逻辑结构,不必再依靠成百上千行代码的帮助。有了 BEA Workshop,在开发 SOA 时,我们不必再四处求助于他人。

作者简介
 David Hritz是NuWave Solutions, LLC的CTO。他还是Creating Web Portals with BEA WebLogic (March 2003)一书的合著者。


版权所有:UML软件工程组织