2011年6月2日星期四

OSB_012:OSB 11g 开发指南之二:利用JCA Adapter “虚拟化”服务

POProcessing只是订单的入口,谁可以下订单呢?
这里我们假设某个ERP系统负责下订单,该系统负责搜集“需求”,比如根据“进销存”的情况,自动生成生成订单,即“按需下单”。
应用设计如图:Procure-to-Pay是一个“订单生成系统”,Order-to-Cash是“订单处理系统”。



“订单生成系统”最终会把需求数据插入到一张表中:OSB_Requisition。因为这里无法真实模拟ERP系统,所以我们在OSB上建立一个Requisition服务,由它代替ERP系统,完成向OSB_Requisition表插入数据的工作。
由于这里涉及数据库的写操作,因此我们要使用SOA中的Database Adapter。在真实场景中,要换成使用ERP Adapter。不管使用哪种Adapter,在OSB上对应使用的Transport Protocol都是JCA。
基本设计如下:


重要步骤说明:

1. 在JDeveloper中创建SOA项目,拖放Database Adapter到Reference中。
写操作属于Outbound,所以要放在“右边”Reference中。
设置JNDI Name,该值必须在Console中的DbAdapter中可以找到。选择Insert操作。选择主键。



2. 在OSB中创建Requisition项目,选择Create Resource from URL。
URL就是来自SOA项目中的file:/MyProject/SOA/OSBDemo/DBArtifacts/createRequisition_db.jca。
Resource Type选择JCA Binding。



3. 因为是Outbound服务,可以根据JCA 文件自动创建Business Service。



4. 根据已有的Business Service创建Proxy Service。
注意Transport Protocol要选择HTTP,因为Proxy Service是对外公开的。
Message Flow的设计:记录REQ_ID的信息,然后直接路由到Business Service。

5. 测试Proxy Service,可以测试三种情况,如果成功,应该在表OSB_Requisition中看到记录。

(1)<$1000的小订单
<cre:OsbRequisitionCollection xmlns:cre="http://xmlns.oracle.com/pcbpel/adapter/db/top/createRequisition">
<cre:OsbRequisition>
<cre:requisitioner>Bob</cre:requisitioner>
<cre:reqid>2222</cre:reqid>
<cre:productname>iPod Shuffle</cre:productname>
<cre:item>1GB</cre:item>
<cre:itemtype>Electronics</cre:itemtype>
<cre:reqDate>March 16, 2010</cre:reqDate>
<cre:description>string</cre:description>
<cre:quantity>1.00</cre:quantity>
<cre:price>500.00</cre:price>
<cre:currency>USD</cre:currency>
<cre:deliverydate>April 16, 2010</cre:deliverydate>
<cre:plant>Boulder</cre:plant>
<cre:cctype>Mastercard</cre:cctype>
<cre:ccnumber>1234-1234-1234-1234</cre:ccnumber>
</cre:OsbRequisition>
</cre:OsbRequisitionCollection>

(2)>$1000 and <$5000的大订单

<cre:OsbRequisitionCollection xmlns:cre="http://xmlns.oracle.com/pcbpel/adapter/db/top/createRequisition">
<cre:OsbRequisition>
<cre:requisitioner>Bob</cre:requisitioner>
<cre:reqid>3333</cre:reqid>
<cre:productname>iPod Shuffle</cre:productname>
<cre:item>1GB</cre:item>
<cre:itemtype>Electronics</cre:itemtype>
<cre:reqDate>March 16, 2010</cre:reqDate>
<cre:description>string</cre:description>
<cre:quantity>5.00</cre:quantity>
<cre:price>500.00</cre:price>
<cre:currency>USD</cre:currency>
<cre:deliverydate>April 16, 2010</cre:deliverydate>
<cre:plant>Boulder</cre:plant>
<cre:cctype>Mastercard</cre:cctype>
<cre:ccnumber>1234-1234-1234-1234</cre:ccnumber>
</cre:OsbRequisition>
</cre:OsbRequisitionCollection>

(3)>$5000的超大订单

<cre:OsbRequisitionCollection xmlns:cre="http://xmlns.oracle.com/pcbpel/adapter/db/top/createRequisition">
<cre:OsbRequisition>
<cre:requisitioner>Bob</cre:requisitioner>
<cre:reqid>4444</cre:reqid>
<cre:productname>iPod Shuffle</cre:productname>
<cre:item>1GB</cre:item>
<cre:itemtype>Electronics</cre:itemtype>
<cre:reqDate>March 16, 2010</cre:reqDate>
<cre:description>string</cre:description>
<cre:quantity>20.00</cre:quantity>
<cre:price>500.00</cre:price>
<cre:currency>USD</cre:currency>
<cre:deliverydate>April 16, 2010</cre:deliverydate>
<cre:plant>Boulder</cre:plant>
<cre:cctype>Mastercard</cre:cctype>
<cre:ccnumber>1234-1234-1234-1234</cre:ccnumber>
</cre:OsbRequisition>
</cre:OsbRequisitionCollection>

数据进入向OSB_Requisition表后,我们使用一个触发器向OSB_PurchaseOrder表中插入数据,但是还需要“有人”来读取OSB_PurchaseOrder表的数据,从而触发POProcessing。
由于这里涉及数据库的读操作,我们同样要使用SOA中的Database Adapter。
基本设计如下:


重要步骤说明:

1. 在JDeveloper中打开SOA项目,拖放Database Adapter到Service中。
写操作属于Inbound,所以要放在“左边”Service中。
设置JNDI Name,该值必须在Console中的DbAdapter中可以找到。选择Poll操作。选择读取记录后删除。选择主键。

2. 在OSB中创建Requisition项目,选择Create Resource from URL。
URL就是来自SOA项目中的file:/MyProject/SOA/OSBDemo/DBArtifacts/receivePO_db.jca。
Resource Type选择JCA Binding。

3. 因为是Inbound服务,可以根据JCA 文件自动创建Proxy Service。
URL就是来自SOA项目中的file:/MyProject/SOA/OSBDemo/DBArtifacts/receivePO_db.jca。
Resource Type选择JCA Binding。

4. 根据POProcessing中的入口ReceivePO的WSDL创建Business Service。
URL就是来自SOA项目中的file:/MyProject/SOA/OSBDemo/DBArtifacts/receivePO_db.jca。
Resource Type选择JCA Binding。

5. 修改Proxy Service中的Message Flow,增加记录和转换功能。
其中最关键的是如何把从数据库表OSB_PurchaseOrder中读出的数据格式,转化成POProcessing接受的数据格式。
XQuery可以作为转换器,脚本如下:
declare namespace ns1 = "http://xmlns.oracle.com/pcbpel/adapter/db/top/receivePO";
declare namespace ns0 = "http://xmlns.oracle.com/ns/order";
declare namespace xf = "http://tempuri.org/PO%20Processing/Resources/dbPO_to_soaPO/";

declare function xf:dbPO_to_soaPO($osbPurchaseorder1 as element())
as element(ns0:PurchaseOrder) {
let $OsbPurchaseorder := $osbPurchaseorder1
return
<ns0:PurchaseOrder>
<ns0:CustID>{ data($OsbPurchaseorder/ns1:custid) }</ns0:CustID>
<ns0:ID>{ data($OsbPurchaseorder/ns1:id) }</ns0:ID>
{
for $productname in $OsbPurchaseorder/ns1:productname
return
<ns0:productName>{ data($productname) }</ns0:productName>
}
{
for $itemtype in $OsbPurchaseorder/ns1:itemtype
return
<ns0:itemType>{ data($itemtype) }</ns0:itemType>
}
{
for $price in $OsbPurchaseorder/ns1:price
return
<ns0:price>{ data($price) }</ns0:price>
}
{
for $quantity in $OsbPurchaseorder/ns1:quantity
return
<ns0:quantity>{ data($quantity) }</ns0:quantity>
}
{
for $status in $OsbPurchaseorder/ns1:status
return
<ns0:status>{ data($status) }</ns0:status>
}
{
for $cctype in $OsbPurchaseorder/ns1:cctype
return
<ns0:ccType>{ data($cctype) }</ns0:ccType>
}
{
for $ccnumber in $OsbPurchaseorder/ns1:ccnumber
return
<ns0:ccNumber>{ data($ccnumber) }</ns0:ccNumber>
}
</ns0:PurchaseOrder>
};

declare variable $osbPurchaseorder1 as element() external;

xf:dbPO_to_soaPO($osbPurchaseorder1)

6. 测试Receive PO服务,分三种情况测试。
我们通过测试Requisition服务,从而间接地测试Receive PO服务。
因为测试Requisition服务时,会插入数据到OSB_Requisition表中,OSB_Requisition表上的触发器会把数据插入到表OSB_PurchaseOrder中,Receive PO服务会轮询OSB_PurchaseOrder表,一旦有数据后,会把数据转换并路由到POProcessing。
测试时,有一点感觉不太方便,因为我选择了读取OSB_PurchaseOrder表后就删除数据,
触发器的速度和轮询的速度一般要快于我查看的速度,所以无法判断是否真的有数据插入了OSB_PurchaseOrder表。
当然我可以根据Report记录,和POProcessing是否有新实例产生来判断,但多少有些麻烦。
如果OSB上有“暂停”某个服务的功能就好了,这样我可以先暂停Receive PO服务,测试Requisition服务,发现OSB_PurchaseOrder表中有数据后,再启动Receive PO服务,看看数据是否被读取并删除了。

总结:
当我们需要访问ERP或数据库这些比较“成熟而公认”的系统时,Oracle SOA 提供了对应的Adapter供你使用。
然后,在OSB上,Transport Protocol可以以JCA的方式与这些系统集成,非常方便,无需编码。
在数据格式转换环节,我们可以使用XQuery来实现。
这样,就完全实现了“服务虚拟化”:服务的请求者无需知道服务的提供者的具体技术实现,it just know, there is a service can satisfy its request,that is it.

3 条评论:

Essayprovider 说...

恭喜!你的巨大努力。请继续保持。
Thesis Writing

千红一窟 说...

谢谢鼓励!我会的。

匿名 说...

你好,想问下你的osb_001到015是连续的吗,中间很多号断了还是我没找到?