当工作流与多个不同系统交互时,如在这里进行价格和可用性处理时,可以通过并行地执行任务提高工作流的能力。当需要创建两个或者更多这种并行执行的分支时就可向工作流添加Parallel节点。
要了解有关Parallel节点的内容,参见理解工作流中的并行执行。
创建Parallel节点
在工作流中添加Parallel节点
1. 在Application窗格,单击RequestQuote.jwf 以确保工作流显示在Design View中。
2. 单击Palette中的 Parallel。然后将Parallel节点拖到Design View中的工作流上,释放到For Each循环中。Design View会更新以包含Parallel节点的表示,如下图所示。
3. 改变在Parallel节点中的分支名字以标识工作流并行执行的动作:
· 双击左边Branch的标签并输入 Get Price。
· 双击右边Branch的标签并输入Get Availability。
关于Join条件的说明
在默认情况下,Parallel节点指定一个AND 联合条件。在这里,在所有分支中的动作都必须在执行流程进入parallel节点后面的节点之前完成。
如果指定了OR联合条件,那么当一个分支中的动作完成时,所有其他分支中的动作就会中止,执行流程就会进入Parallel节点后面的节点。
对于RequestQuote工作流,因为希望Parallel节点的两个分支都要完成,所以不改变默认的AND联合条件。
可以在 Property Editor中查看并编辑Parallel节点的联合条件。如果在Parallel节点的顶部或者在Design View中在节点的边线处选择了 ,那么Parallel节点的属性就会显示在 Property Editor中。例如,在 Property Editor中这里的Parallel节点应该与下图所示的相同:
相关主题
理解工作流中的并行执行
创建结合价格和可用性数据的逻辑
在本节中将学习如何:
· 从所创建的并行分支(通过控件)调用价格和可用性服务。
· 在分支上设计回调以等待并处理来自控件的响应。
· 构建XML文档,将For Each循环中每一次枚举从控件得到的响应数据附加到这个文档上(在Design View中查看工作流:parallel节点在For Each循环中,意味着执行流程在每一次枚举时都通过Parallel节点)。
工作流中的并行执行分支是逻辑地并行的,物理上分支是由工作流引擎串行执行的。
在我们的示范方案中,工作流必须确定价格和可用性信息,这样才能准备报价并返回给客户。这个工作流可以从并行方式获益,因为它与两个不同的外部系统通信并期待从这些外部系统得到响应。
外部系统可以是任何返回工作流所需要信息的资源(其他工作流、Web服务、EJB、数据库等等)。工作流通过控件与资源交互。本教程使用了两个Web服务:一个返回客户请求文档中指定的每一个widgetID的价格,第二个服务根据widgetID以及请求文档所要求的数量返回可用性信息。RequestQuote工作流用来进行交互的控件是在项目文件夹(/Tutorial/requestquote/services)中提供的:PriceProcessorControl.jcx 和AvailabilityProcessorControl.jcx 。
设计Parallel节点与价格和可用性Web服务交互,完成下列任务:
· 在工作流中添加控件节点
· 在项目中创建PriceProcessor和AvailProcessor控件的实例
· 创建变量以接收价格和可用性数据
· 设计Get Price分支的动作
· 设计Get Availability分支的动作
在工作流中添加控件节点
必须向Parallel节点的每一个分支添加下面节点之一:Control Send、Control Receive、Control Send with Return。
为此,在Palette中选择相应的节点(( Control Send、 Control Receive 或者 Control Send with Return),将节点拖到Design View中的工作流上——将节点释放到Parallel分支上,直到创建了像下图那样的Parallel组:
以这种式将各个分支设计为如下的执行流程:
1. 从Control Send节点调用资源(通过控件)。
2. 在Control Receive节点等待来自控件的响应。
3. 在Control Send with Return节点进行对控件的同步调用。在这个节点,调用构建XML文档的Transformation控件,在For Each循环中每一次枚举时从控件得到的响应数据会附加到这个文档中。
在项目中创建PriceProcessor和AvailProcessor控件
Web服务控件(PriceProcessorControl.jcx和PriceProcessorControl.jcx)是在应用程序的项目中提供的(具体是在Tutorial/requestquote/services 文件夹中)。本节的目标是描述如何在工作流中创建合适的节点,并设计工作流与这些控件的通信。
1. 在Contorl 选项卡上单击Add以显示表示工作流可以与之交互的资源的控件列表。
2. 选择Web Service。会显示Insert Contorl对话框。
3. 在 Insert Control对话框中,输入PriceProcessor作为这个控件的变量名。然后,确保选中了下列选项:Use a Web Service control already defined by a JCX file。
4. 单击 JCX file 域旁边的Browse,选择 /Tutorial/requestquote/services文件夹中的PriceProcessorControl.jcx,然后单击Select以关闭文件浏览器。
5. 单击Create以关闭 Insert Control 对话框。在项目中创建了Web控件的一个实例并显示在Controls选项卡上。
6. 重复第1到第5步,但是输入AvailProcessor作为控件的变量名,并选择下面文件夹中已经定义的AvailProcessorControl.jcx作为要实例化的控件文件:/Tutorial/requestquote/services。
创建变量以接收价格和可用性数据
在这一步,创建变量(price和avail)以接收由价格和可用性服务返回工作流的价格数据和可用性数据。然后再创建2个变量,用于接收通过For Each循环的每一次枚举返回的数据结合而成的价格和可用性列表。完成下列步骤:
1. 在Variables选项卡中,单击Add —> Variable以显示Create Variable对话框。
2. 在Variable Name域中,输入price。
3. 在Select Variable Type域中,单击XML Types中priceQuote.xsd 旁边的+以展开列表,然后选择列表中的priceRequests。Variable Type 域会填入org.example.price.PriceRequestsDocument。
4. 单击OK。会创建了新的工作流变量并作为XML Type变量列在Variables选项卡中。
5. 在 Variables选项卡中,单击Add —> Variable以显示 Create Variable对话框。
6. 在Variable Name域中,输入avail。
7. 在Select Variable Type域中,单击XML Types中availQuote.xsd旁边的+以展开列表,然后选择列表中的availRequest。域中会填入org.example.price.AvailRequestDocument。
8. 单击OK。会创建新的工作流变量并作为XML变量列在Variables选项卡中。
9. 在Variables选项卡中,单击Add —> Variable 以显示Create Variable对话框。
10. 在Variable Name域中,输入priceList。
11. 在 Select Variable Type域,单击Java Types旁边的+以展开列表,然后选择列表中的XmlObjectList。
Variable Type 域会填入com.bea.xml.XmlObjectList。
12. 单击OK。会创建新工作流变量并作为XML变量列在Variables选项卡中。要了解XmlObjectList数据类型,参见关于使用XmlObjectList数据类型的说明。
13. 在Variables选项卡中,单击Add —> Variable以显示Create Variable对话框。
14. 在Variable Name域中输入availList。
15. 在Select Variable Type域中,单击Java Types 旁边的+以展开列表,然后从列表中选择XmlObjectList。
Variable Type域填入了com.bea.xml.XmlObjectList。
16. 单击OK。会创建新工作流变量并作为XML变量列在Variables选项卡中。
在本节,在项目中添加了四个变量。项目中的所有变量都列在Data Palette中的Variables选项卡中。它应该与下图相同:
关于使用XmlObjectList数据类型的说明
在For Each循环的每一次枚举中,PriceProcessor服务返回价格数据,它被赋值给price变量,而AvailProcessor服务返回可用性数据,它被赋值给avail变量。工作流必须收集每一次枚举所返回的价格数据并创建一个价格数据列表,循环中每一次枚举都会向列表中加入一项。与此类似,在Parallel节点的Get Availability分支上循环中的各次枚举都会创建一个可用性数据列表。
XmlObjectList是一种Java数据类型,它指定一系列non-typed XML格式数据。换句话说,这个数据类型表示了一组XML元素的(一组重复的元素)。作为Parallel节点的Get Price分支中每一次枚举的最后一步,工作流将price变量的数据(类型为XmlObjectList)赋值给priceList变量。这样,就用一个变量接收了For Each循环枚举的Request for Quote中的每一个widget的价格数据。同样,只用一个变量接收了每一个widget的可用性数据。
要了解如何使用XmlObjectList变量,参见设计Create PriceList节点和设计Create AvailList节点。
设计Get Price分支的动作
像下面这样重新命名Get Price分支中的节点(以它们执行的顺序):: Request Price、Receive Price、Create PriceList。完成下面的任务:
1. 双击 Request Price节点以打开它的节点构造器。 节点构造器是在General Settings选项卡中打开的。
2. 单击Control域旁边的箭头以显示项目中控件实例的下拉列表。
3. 选择 PriceProcessor。Method面板出现了可以对控件调用的asynchronous send methods列表。
4. 从列表中选择下面的方法:void getPrice(int arg1)
5. 单击Apply。
6. 单击Send Data以打开节点构造器的第二个选项卡。
Method Expects域填入了PriceProcessor Web服务开放的getPrice()方法所期待的数据类型。
注:PriceProcessor 服务取widgetID作为输入并返回该widget的价格。getPrice()方法是以整数值widgetID作为输入的。
7. 单击Select Variable 以显示项目中的变量。然后选择iter_requestXML1 (WidgetRequestDocument)。
在指定For Each循环所枚举的重复元素时就创建了枚举变量。在运行时,它拥有当前widgetRequest元素——即在For Each循环中当前处理的元素(参见设计工作流中的For Each循环)。
注意控件所要求的输入数据类型是Java基类(int),用于储存请求的widgetID和数据数量的枚举变量是XML类型(对于QuoteRequest.xsd XML Schema是有效的)。
在这里,向Transformation控件添加一个新的transformation方法,这个控件是在创建Decision逻辑和对taxCalculation控件的调用时已经在项目中创建的。
8. 在Send Data 选项卡的Step 2a 中,确保Control Instance域填入了在项目Transformations中已经创建的Transformation控件的名字。
9. 在Transform Method域中输入toPriceProcess。
10. 单击Edit Transformation。
映射工具会打开并在Source Schema 窗格中显示 iter_requestXML1变量的一种表示,同时在Target Schema窗格中显示一个int。
11. 在 Source Schema窗格中单击 widgetID并将鼠标拖到 Target Schema 窗格中的 int。在 XML Map窗格中会在widgetID和int元素之间画出一条线。它表示这两种数据类型之间的映射。
12. 单击OK以保存映射并关闭映射工具。
注:一个XQuery表达式被写入文件Transformations.drf中以反映上面步骤中在transformation mapper中所做的工作。可以在Application窗格中双击Transformations.dtf在设计和源代码视图中查看XQuery表达式。
13. 单击Apply,然后单击 Request Price节点构造器中的Close以保存为这个节点所做的规定,并关闭其节点构造器。
这一步完成了对Request Price节点的设计。
1. 双击Receive Price节点以打开其节点构造器。节点构造器是在General Settings选项卡中打开的。
2. 单击Control域旁边的箭头以显示项目中控件实例的列表。
3. 选择PriceProcessor。Method面板加入了PriceProcessor控件上的asynchronous receive methods列表。
4. 从列表中选择下列方法:
void returnPrice(int arg1, float arg2)
5. 单击Receive Data以打开节点构造器的第二个选项卡。
Method Returns域填入了PriceProcessor Web服务上的returnPrice()方法返回的数据类型。
注:PriceProcessor服务取widgetID做为输入并返回一个int和一个float——它们分别包含widgetID和价格的值。
6. 在Receive Data选项卡,单击Select Variable以显示项目中的变量。
7. 选择 price (PriceRequestsDocument)。
注意returnPrice() 方法返回 一个 int (widgetID) 和一个 float (price)。因为希望将返回数据赋值给price变量,而它是一个XML类型,所以必须向在项目中已经创建的Transformation控件添加另一个transformation方法。
8. 在Step 2a中,确保Control Instance域中填入已经创建的Transformation控个的名字:Transformations。
9. 在 Transform Method域中输入priceToXML。
10. 单击 Edit Transformation。
这会打开映射工具并在Source Schema窗格显示 int和float的表示,在Target Schema 窗格显示price变量的表示。 11. 将Source Schema窗格中的 $_intDoc和$_floatDoc分别映射到窗格中的widgetId和price。
12. 单击Ok以保存所做的映射并关闭映射工具。
13. 单击Apply,然后单击Receive Price节点构造器的Close以保存对该节点所做的规定并关闭节点构造器。
这一步完成了对Receive Price节点的设计。
在这一步,用项目中提供的Transformation控件(PriceAvailTransforms)将由PriceProcessor控件(在For Each循环中的每一次枚举中)返回的价格数据附加到一个变量中。
在前面为工作流中设计的节点中,根据需要创建transformation方法以映射工作流发送给客户和控件以及从客户和控件接收的的数据。在这里也要使用Transformation控件,但是使用的方式不同。对于Create PriceList节点,数据不发送给客户或者控件。相反,Transformation控件取工作流的输入——typed XML数据并返回non-typed XML (XmlObject)。工作流必须将For Each循环中的每一次枚举所返回的数据附加到一个变量中,从而创建了一组重复的XML数据。可以接收这种来自For Each循环的重复XML数据的变量为XmlObjectList类型。只有附加到XmlObject类型的变量的数据可以附加到XmlObjectList类型的变量中(参见有关使用XmlObjectList数据类型的说明)。
1. 在项目中通过完成下列任务创建 PriceAvailTransforms控件的一个实例:
a. 如果Controls选项卡在WebLogic Workshop中不可见,则从菜单栏中选择View —> Windows —> Data Palette。
b. 单击Controls选项卡中的Add以显示表示工作流可以与之交互的控件的下拉列表。
c. 选择Transformation。显示Insert Control 对话框。
d. 在Insert Control对话框,输入PriceAvailTransforms 作为这个控件的变量名。
确保选择了下列选项:Use a Transformation control already defined by a DTF file。
单击DTF file域旁边的Browse,选择项目文件夹Tutorial/requestquote中的PriceAvailTransform.dtf,然后单击Select以关闭文件浏览器。
e. 单击Create以关闭Insert Control对话框。
在项目中创建了名为PriceAvailTransforms的Transformation控件实例,并显示在 Controls 选项卡中。
注:对于创建这个PriceAvailTransform.dtf控件的说明超出了本教程范围。要了解有关Transformation控件的更内容,参见有关Transformation Controls的说明。
2. 双击Create PriceList 节点打开它的节点构造器。节点构造器在General Settings选项卡中打开。
3. 单击Control域旁边的箭头以显示项目中控件实例的下拉列表。
4. 选择PriceAvailTransforms。Method面板显示这个Transformation控件上的synchronous methods列表。
5. 选择列表中的下列方法:
XmlObject convertPriceXMLtoXMLObj()
6. 单击Send Data以打开节点构造器中的第二个选项卡。
Method Expects域中填入了Transformation控件PriceAvailTransforms的convertPriceXMLtoXMLObj() 方法所期待的数据类型。
7. 在 Send Data选项卡中,单击Select Variable以显示项目中的变量。
8. 选择 price (PriceRequestsDocument)。
在这里,注意price变量的数据类型(PriceRequestsDocument)与控件所期待的数据相匹配。
9. 单击Apply。
10. 单击Receive Data以打开节点构造器的第三个选项卡。
Method Returns域中填入了Transformation控件PriceAvailTransforms 上的convertPriceXMLtoXMLObj() 方法所返回的数据类型:XmlObject。XmlObject对象是一种Java数据类型,它指明数据为non-typed XML格式。换句话说,这种数据类型表示了对于XMLSchema无效的XML数据。
11. 在Receive Data选项卡上,单击Select Variable以显示项目中的变量。
12. 选择priceList (XmlObjectList)。
在这一步,工作流将XmlObject附加到priceList变量,XmlObject包含了由控件(在For Each循环中的当前枚举中)返回的数据。
13. 单击Apply,然后单击Close以保存所做的规定并关闭节点构造器。
这一点完成了对Parallel节点上Get Price分支的设计。
14. 选择 File —> Save All 以保存到目前为止所做的工作。
设计Get Availability分支的动作
将Get Availability 分支的节点像后面这样重新命名(按照它们执行的顺序): Request Availability、Receive Availability、Create AvailList。
完成下列任务:
1. 双击Request Availability节点以打开其节点构造器。节点构造器会在General Settings选项卡中打开。
2. 单击Control域旁边的箭头以显示项目中可用的控件实例列表。
3. 选择AvailProcessor。Method面板显示可以对控件调用的asynchronous send methods列表。
4. 从列表中选择下列方法:
void getAvail(int arg1, int arg2)
5. 单击Send Data以打开节点构造器的第二个选项卡。
Method Expects 域填入了AvailProcessor Web服务开放的getAvail()方法所期待的数据类型。
注:AvailProcessor服务取客户请求的widgetID (int)和quantity (int)作为输入。它返回widgetId (int)、可用数量 (int)、表示该widget是否有库存的布尔值和发货日期 (String).。
6. 单击Select Variable以显示项目中的变量。然后选择iter_requestXML1 (WidgetRequestDocument)。
注意PriceProcessor控件要求的输入数据类型是Java基类(int),而储存widgetID和数量数据的枚举变量是XML类型(对QuoteRequest.xsd XMLSchema有效)。
在这里,向项目中的Transformation控件添加一个新的transformation方法。
7. 在 Step 2a中,确保Control Instance域填入了已经创建的Transformation控件的名字:Transformations。
8. 在Transform Method域中输入toAvailProcess。
9. 单击Create Transformation。
这会打开映射工具并Source Schema窗格中显示iter_requestXML1变量的表示,在Target Schema窗格中显示一个 int的表示。
10. 如下创建transformation:
· 将Source Schema窗格中的widgetID映射为Target Schema窗格中的arg1。
· 将Source Schema窗格中的quantity映射为Target Schema窗格中的arg2 。
11. 单击OK以保存所做的并关闭映射工具。
注:在Transformations.dtf中写入了一个XQuery表达式以反映在前面步骤中在transformation映射器中所做的工作。
12. 单击Apply,然后单击Request Availability节点构造器中的Close以保存对该节点所做的规定,并关闭节点构造器。
这一点完成了对 Request Availability节点的设计。
1. 双击Receive Availability节点以打开其节点构造器。节点构造器会在General Settings选项卡中打开。
2. 单击Control域旁边的箭头以显示项目中可用的控件实例列表。
3. 选择AvailProcessor。Method面板中会显示AvailProcessor控件上的asynchronous receive methods列表。
4. 选择列表中的下列方法:
void avail(int arg1, int arg2, boolean arg3, String arg4)
5. 单击 Receive Data以打开构节构造器的第二个选项卡。
Method Returns域中填入了AvailProcessor Web服务上的avail() 方法所返回的数据类型。
6. 在Receive Data 选项卡上,单击Select Variable以显示项目中的变量。
7. 选择avail (AvailRequestDocument)。
注意方法返回一个int (widgetID)、一个int(可用数量)、一个布尔值(表示该widget是否有库存)和一个String(发货日期)。因为希望将数据赋值给avail变量,而它是一个XML类型,所以必须向项目中的Transformation控件添加另一个transformation方法。
8. 在Step 2a中,确保Control Instance域中填入了已经创建的Transformation控件的名字:Transformations。
9. 在Transform Method域中输入availToXML。
10. 单击Create Transformation。
这会打开映射工具并在Source Schema窗格中显示该项数据类型的一个表示,在Target Schema窗格中显示availRequest变量的表示。
11. 将Source Schema值映射到Target Schema,如下图如所。
12. 单击OK以保存所做的映射并关闭映射工具。
13. 单击Apply,然后单击Receive Availability 节点构造器中的Close以保存对该节点所做的规定并关闭节点构造器。
这一步完成了对Receive Availability节点的设计。
在设计Parallel节点的Get Price分支时,用同样的方式设计工作流以将价格数据附加到一个变量中,在这一步中,调用PriceAvailTransforms Transformation控件的一个方法将可用性数据返回到一个类型为XmlObjectList的变量中。
1. 双击Create AvailList节点以打开其节点构造器。节点构造器会在General Settings 选项卡中打开。
2. 单击Control域旁边的箭头以显示项目中可用控件实例的列表。
3. 选择PriceAvailTransforms。Method面板显示这个Transformation控件的synchronous methods 列表。
4. 选择列表中的下列方法:
XmlObject convertAvailXMLtoXMLObj()
5. 单击 Send Data以打开节点构造器中的第二个选项卡。
Method Expects域中会填入PriceAvailTransforms控件上的convertAvailXMLtoXMLObj()方法所期待的数据类型。
6. 在 Send Data选项卡上,单击 Select Variable以显示项目中的变量。
7. 选择avail (AvailRequestDocument)。
在这里,注意avail变量的数据类型 (AvailRequestDocument) 与由PriceAvailTransforms控件返回的数据相匹配。
8. 单击Apply。
9. 单击Receive Data以打开节点构造器中的第三个选项卡。
Method Returns域中会填入由PriceAvailTransforms 控件上的convertAvailXMLtoXMLObj()方法所返回的数据类型:XmlObject。这种数据类型表示XML数据对XML Schema是无效的。
10. 在Receive Data选项卡上,单击Select Variable 以显示项目中的变量。
11. 选择availList (XmlObjectList)。
在这一步中,工作流会将包含由AvailProcessor控件(在For Each循环的当前枚举中)返回的数据的XmlObject附加到availList变量上。
12. 单击Apply,然后单击Close以保存所做的规定并关闭节点构造器。
这一步完成了对Parallel节点的Get Availability分支的设计。Parallel节点宣告完成。
在运行时,当工作流退出For Each节点时,就完成了确定客户在Request for Quote消息报中请求的项目的价格和可用数量的工作。
在工作流的这一点上,由PriceProcessor控件返回的报价数据赋值给了priceList变量,而由AvailProcessor控件返回的可用数量数据赋值给了availList变量。