- 浏览: 35279 次
- 性别:
- 来自: 北京
最新评论
SOA Suite 11g 开发指南之十:增加异常处理
- 博客分类:
- SOA
声明:该博文来自热爱JAVA,热爱生活。原文地址http://maping930883.blogspot.com/
Oracle SOA Suite 提供了复杂而精致的异常处理机制,你可以定义异常处理器来处理不同层次的异常,包括系统异常和应用异常。
BPEL的规范中提供了如何捕捉和处理异常,详细说明请参考《BPEL 如何处理异常?》。
但SOA应用中不光是BPEL组件,还有其它组件,比如Mediator。而Mediator并没有提供有关异常的规范,那么该如何处理Mediator中的异常呢?
为此,Oracle SOA Suite 提供了一个基于策略的异常处理机制,这些策略可以绑定到整个SOA 应用或者应用中的一个组件,比如Mediator。
在这个实验中,我们将首先处理基于策略的异常,然后再处理BPEL的异常。
1. 基于策略的异常
为了模拟remote fault,在EM中,我们把getStatusByCC服务Shutdown,输入大订单测试。
(1)remote fault异常
(2)增加策略文件:fault-policies.xml。与POProcessing中的composite.xml文件在同一目录。
<!-- Step #1: Add your fault handler for remote fault here: -->
<faultName xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
name="bpelx:remoteFault">
<condition>
<action ref="ora-human-intervention"/>
</condition>
</faultName>
(3)增加策略文件:fault-bindings.xml。与POProcessing中的composite.xml文件在同一目录。
<?xml version="1.0" encoding="UTF-8" ?>
<faultPolicyBindings version="2.0.1"
xmlns="http://schemas.oracle.com/bpel/faultpolicy"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<composite faultPolicy="POProcessingFaults"/>
</faultPolicyBindings>
(4)重新发布POProcessing,重新测试大订单。发现该异常是可以恢复重试的。
(5)重启getStatusByCC服务,点击Recover重试。
2. 处理BPEL异常
BPEL的规范中提供了如何捕捉和处理异常,因此发生在BPEL中的异常最好使用规范中的处理办法。
目前,validateForCC的实现:如果传入一个不存在的信用卡号,validateForCC只是简单的返回一个空响应。这个空响应不太直观,因为返回空响应可能还有其它原因。
现在,修改validateForCC的实现如下:如果传入一个不存在的信用卡号,将会抛出一个UnkonwCC的异常。在BPEL中可以捕捉到这个异常,然后进行处理。这样的修改在设计上更加合理。
2.1 实验准备:创建VALIDATECC存储过程
该存储过程用来验证信用卡是否存在,如果不存在抛出应用异常:-20001, 'UNKNOWN CREDIT CARD'。
sqlplus soademo/soademo @create_validate_cc.sql
create or replace FUNCTION VALIDATECC(cc_number IN VARCHAR2)
RETURN VARCHAR2 AS
l_status CREDITCARDINFO.STATUS%TYPE;
BEGIN
select status
into l_status
from creditcardinfo
where ccnumber = cc_number;
RETURN l_status;
EXCEPTION
WHEN NO_DATA_FOUND THEN
raise_application_error(-20001, 'UNKNOWN CREDIT CARD');
END VALIDATECC;
/
2.2 修改ValidateForCC,增加validateCC Reference。
Meditor过滤条件如下:以2开头的信用卡号调用validateCC,返回'code=20001'的异常;
不以2开头的信用卡号调用getCreditValidation。
拖放Database Adapter,并设置如下:
2.3 修改ApproveLargeOrder BPEL。
把invokeCCStatusService放入一个Scope中,并为这个Scope添加一个Catch分支,捕捉bindingFault异常。
这里有一个BUG:默认生成的.bpel文件中定义的变量是<variable messageType="bpelx:bindingFault" name="FaultVar"/>
但实际上,没有地方定义类型bpelx:bindingFault,应该改成如下的样子:
<variable messageType="bpelx:RuntimeFaultMessage" name="FaultVar"/>
否则,编译时会报错:WSDL messageType "{http://schemas.oracle.com/bpel/extension}bindingFault" of variable "" is not defined in any of the WSDL files。
2.4 修改fault-policies.xml。
由于上一个实验中设置了基于策略的异常处理,而基于策略的异常处理优先于BPEL的异常处理,所以以下的设置是让基于策略的异常处理啥都不做,直接抛出异常,由BPEL异常处理来接管。
<!-- Step #2: Add your fault handler for binding fault here: -->
<faultName xmlns:bpelx="http://schemas.oracle.com/bpel/extension" name="bpelx:bindingFault">
<condition>
<!-- Let the component handle this specific binding fault -->
<test>$fault.code="20001"</test>
<action ref="ora-rethrow-fault"/>
</condition>
</faultName>
2.5 测试大订单,订单号以2开头。
你会发现ApproveLargeOrder中,异常被异常策略框架抛出,然后由BPEL异常框架捕捉到并处理。
3. 使用Java Fault Handler捕捉和处理异常。
3.1 MyFaultHandler.java
package soatraining.faulthandling;
import java.io.File;
import java.io.PrintStream;
import java.util.*;
import oracle.integration.platform.faultpolicy.IFaultRecoveryContext;
import oracle.integration.platform.faultpolicy.IFaultRecoveryJavaClass;
public class MyFaultHandler
implements IFaultRecoveryJavaClass
{
public MyFaultHandler()
{
}
public void handleRetrySuccess(IFaultRecoveryContext ifc)
{
print("RertySuccess");
}
public String handleFault(IFaultRecoveryContext ifc)
{
print("Handle Fault");
print("Properties");
print("=================================================================");
Map props = ifc.getProperties();
java.util.Map.Entry entry;
for(Iterator iterator = props.entrySet().iterator(); iterator.hasNext(); print((new StringBuilder()).append((String)entry.getKey()).append(" = ").append(((ArrayList)entry.getValue()).get(0)).toString()))
entry = (java.util.Map.Entry)iterator.next();
String logFileName = (String)((ArrayList)props.get("logFileName")).get(0);
String logFileDir = (String)((ArrayList)props.get("logFileDir")).get(0);
PrintStream ps = null;
try
{
ps = new PrintStream((new StringBuilder()).append(logFileDir).append(File.separator).append(logFileName).toString());
}
catch(Exception e)
{
print(e.getMessage());
}
log(ps, "Fault Details");
log(ps, "===============================================================");
log(ps, (new StringBuilder()).append("Fault Type ................ ").append(ifc.getType()).toString());
log(ps, (new StringBuilder()).append("Poilcy ID ................. ").append(ifc.getPolicyId()).toString());
log(ps, (new StringBuilder()).append("Faulted Partner Link ...... ").append(ifc.getReferenceName()).toString());
log(ps, (new StringBuilder()).append("Port Type ................. ").append(ifc.getPortType()).toString());
return "OK";
}
private void log(PrintStream ps, String s)
{
try
{
ps.println(s);
}
catch(Exception e)
{
print(e.getMessage());
}
}
private void print(String s)
{
System.out.println((new StringBuilder()).append("MyFaultHanlder: ").append(s).toString());
}
}
3.2 修改fault-policies.xml。
<!-- Step #2: Add your fault handler for binding fault here: -->
<faultName xmlns:bpelx="http://schemas.oracle.com/bpel/extension" name="bpelx:bindingFault">
<condition>
<!-- Let the component handle this specific binding fault -->
<test>$fault.code="20001"</test>
<action ref="my-java-handler"/>
</condition>
</faultName>
3.3 测试。
查看my-java-handler的定义,会发现它只是记录一些Log,然后重新抛出异常。
因此,BPEL的异常处理机制最终来接管该异常
4. 使用Java Fault Handler捕捉和处理Mediator异常。
Mediator异常处理只能使用基于策略的方式。
Mediator异常可能来自Adapter异常,可能来自Transformation异常。
我们将使用Java Fault Handler捕捉和处理Mediator的所有异常。
为了模拟Adapter异常,我们将把temp目录改成只读,这样对其进行写操作时将抛出异常。
注意,在Windows平台上,改成只读方式不起作用。即使把该目录换名也不行,File Adapter会自动创建该目录。
4.1 修改fault-policies.xml。
<!-- Step #3: Add your fault handler for mediator faults here: -->
<faultName xmlns:medns="http://schemas.oracle.com/mediator/faults" name="medns:mediatorFault">
<condition>
<action ref="my-mediator-fault-handler"/>
</condition>
</faultName>
<!-- Step #4: Add the Action definition for handling mediator fauls using custom java here:-->
<Action id="my-mediator-fault-handler">
<javaAction className="soatraining.faulthandling.MyFaultHandler"
defaultAction="ora-terminate" propertySet="myMediatorProps">
<returnValue value="OK" ref="ora-human-intervention"/>
</javaAction>
</Action>
<!-- Step #5: Add new property set for MyFaultHandler for logging Mediator faults here:-->
<propertySet name="myMediatorProps">
<property name="logFileName">mediator-faults.log</property>
<property name="logFileDir">c:\po\log</property>
</propertySet>
4.2 修改routePO mediator。
之所以要把“quantity < 1000”的路由从Sequential改成Parallel。
是因为Sequential表明Mediator的调用者和Mediator使用的是同一个Thread和Transaction Context,如果出现Mediator异常,异常将直接返回给调用者,而无法被Java Fault Handler捕捉到。
使用Parallel表明进入Mediator后,将启动一个新Thread和Transaction Context,如果出现Mediator异常,可以被Java Fault Handler捕捉到。
4.3 测试。
EM 中应该提示等待人工恢复,因为策略上设置的是“ora-human-intervention”。
因为我是Win7平台,所以没有测试,以后在Linux上再验证吧。
Oracle SOA Suite 提供了复杂而精致的异常处理机制,你可以定义异常处理器来处理不同层次的异常,包括系统异常和应用异常。
BPEL的规范中提供了如何捕捉和处理异常,详细说明请参考《BPEL 如何处理异常?》。
但SOA应用中不光是BPEL组件,还有其它组件,比如Mediator。而Mediator并没有提供有关异常的规范,那么该如何处理Mediator中的异常呢?
为此,Oracle SOA Suite 提供了一个基于策略的异常处理机制,这些策略可以绑定到整个SOA 应用或者应用中的一个组件,比如Mediator。
在这个实验中,我们将首先处理基于策略的异常,然后再处理BPEL的异常。
1. 基于策略的异常
为了模拟remote fault,在EM中,我们把getStatusByCC服务Shutdown,输入大订单测试。
(1)remote fault异常
(2)增加策略文件:fault-policies.xml。与POProcessing中的composite.xml文件在同一目录。
<!-- Step #1: Add your fault handler for remote fault here: -->
<faultName xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
name="bpelx:remoteFault">
<condition>
<action ref="ora-human-intervention"/>
</condition>
</faultName>
(3)增加策略文件:fault-bindings.xml。与POProcessing中的composite.xml文件在同一目录。
<?xml version="1.0" encoding="UTF-8" ?>
<faultPolicyBindings version="2.0.1"
xmlns="http://schemas.oracle.com/bpel/faultpolicy"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<composite faultPolicy="POProcessingFaults"/>
</faultPolicyBindings>
(4)重新发布POProcessing,重新测试大订单。发现该异常是可以恢复重试的。
(5)重启getStatusByCC服务,点击Recover重试。
2. 处理BPEL异常
BPEL的规范中提供了如何捕捉和处理异常,因此发生在BPEL中的异常最好使用规范中的处理办法。
目前,validateForCC的实现:如果传入一个不存在的信用卡号,validateForCC只是简单的返回一个空响应。这个空响应不太直观,因为返回空响应可能还有其它原因。
现在,修改validateForCC的实现如下:如果传入一个不存在的信用卡号,将会抛出一个UnkonwCC的异常。在BPEL中可以捕捉到这个异常,然后进行处理。这样的修改在设计上更加合理。
2.1 实验准备:创建VALIDATECC存储过程
该存储过程用来验证信用卡是否存在,如果不存在抛出应用异常:-20001, 'UNKNOWN CREDIT CARD'。
sqlplus soademo/soademo @create_validate_cc.sql
create or replace FUNCTION VALIDATECC(cc_number IN VARCHAR2)
RETURN VARCHAR2 AS
l_status CREDITCARDINFO.STATUS%TYPE;
BEGIN
select status
into l_status
from creditcardinfo
where ccnumber = cc_number;
RETURN l_status;
EXCEPTION
WHEN NO_DATA_FOUND THEN
raise_application_error(-20001, 'UNKNOWN CREDIT CARD');
END VALIDATECC;
/
2.2 修改ValidateForCC,增加validateCC Reference。
Meditor过滤条件如下:以2开头的信用卡号调用validateCC,返回'code=20001'的异常;
不以2开头的信用卡号调用getCreditValidation。
拖放Database Adapter,并设置如下:
2.3 修改ApproveLargeOrder BPEL。
把invokeCCStatusService放入一个Scope中,并为这个Scope添加一个Catch分支,捕捉bindingFault异常。
这里有一个BUG:默认生成的.bpel文件中定义的变量是<variable messageType="bpelx:bindingFault" name="FaultVar"/>
但实际上,没有地方定义类型bpelx:bindingFault,应该改成如下的样子:
<variable messageType="bpelx:RuntimeFaultMessage" name="FaultVar"/>
否则,编译时会报错:WSDL messageType "{http://schemas.oracle.com/bpel/extension}bindingFault" of variable "" is not defined in any of the WSDL files。
2.4 修改fault-policies.xml。
由于上一个实验中设置了基于策略的异常处理,而基于策略的异常处理优先于BPEL的异常处理,所以以下的设置是让基于策略的异常处理啥都不做,直接抛出异常,由BPEL异常处理来接管。
<!-- Step #2: Add your fault handler for binding fault here: -->
<faultName xmlns:bpelx="http://schemas.oracle.com/bpel/extension" name="bpelx:bindingFault">
<condition>
<!-- Let the component handle this specific binding fault -->
<test>$fault.code="20001"</test>
<action ref="ora-rethrow-fault"/>
</condition>
</faultName>
2.5 测试大订单,订单号以2开头。
你会发现ApproveLargeOrder中,异常被异常策略框架抛出,然后由BPEL异常框架捕捉到并处理。
3. 使用Java Fault Handler捕捉和处理异常。
3.1 MyFaultHandler.java
package soatraining.faulthandling;
import java.io.File;
import java.io.PrintStream;
import java.util.*;
import oracle.integration.platform.faultpolicy.IFaultRecoveryContext;
import oracle.integration.platform.faultpolicy.IFaultRecoveryJavaClass;
public class MyFaultHandler
implements IFaultRecoveryJavaClass
{
public MyFaultHandler()
{
}
public void handleRetrySuccess(IFaultRecoveryContext ifc)
{
print("RertySuccess");
}
public String handleFault(IFaultRecoveryContext ifc)
{
print("Handle Fault");
print("Properties");
print("=================================================================");
Map props = ifc.getProperties();
java.util.Map.Entry entry;
for(Iterator iterator = props.entrySet().iterator(); iterator.hasNext(); print((new StringBuilder()).append((String)entry.getKey()).append(" = ").append(((ArrayList)entry.getValue()).get(0)).toString()))
entry = (java.util.Map.Entry)iterator.next();
String logFileName = (String)((ArrayList)props.get("logFileName")).get(0);
String logFileDir = (String)((ArrayList)props.get("logFileDir")).get(0);
PrintStream ps = null;
try
{
ps = new PrintStream((new StringBuilder()).append(logFileDir).append(File.separator).append(logFileName).toString());
}
catch(Exception e)
{
print(e.getMessage());
}
log(ps, "Fault Details");
log(ps, "===============================================================");
log(ps, (new StringBuilder()).append("Fault Type ................ ").append(ifc.getType()).toString());
log(ps, (new StringBuilder()).append("Poilcy ID ................. ").append(ifc.getPolicyId()).toString());
log(ps, (new StringBuilder()).append("Faulted Partner Link ...... ").append(ifc.getReferenceName()).toString());
log(ps, (new StringBuilder()).append("Port Type ................. ").append(ifc.getPortType()).toString());
return "OK";
}
private void log(PrintStream ps, String s)
{
try
{
ps.println(s);
}
catch(Exception e)
{
print(e.getMessage());
}
}
private void print(String s)
{
System.out.println((new StringBuilder()).append("MyFaultHanlder: ").append(s).toString());
}
}
3.2 修改fault-policies.xml。
<!-- Step #2: Add your fault handler for binding fault here: -->
<faultName xmlns:bpelx="http://schemas.oracle.com/bpel/extension" name="bpelx:bindingFault">
<condition>
<!-- Let the component handle this specific binding fault -->
<test>$fault.code="20001"</test>
<action ref="my-java-handler"/>
</condition>
</faultName>
3.3 测试。
查看my-java-handler的定义,会发现它只是记录一些Log,然后重新抛出异常。
因此,BPEL的异常处理机制最终来接管该异常
4. 使用Java Fault Handler捕捉和处理Mediator异常。
Mediator异常处理只能使用基于策略的方式。
Mediator异常可能来自Adapter异常,可能来自Transformation异常。
我们将使用Java Fault Handler捕捉和处理Mediator的所有异常。
为了模拟Adapter异常,我们将把temp目录改成只读,这样对其进行写操作时将抛出异常。
注意,在Windows平台上,改成只读方式不起作用。即使把该目录换名也不行,File Adapter会自动创建该目录。
4.1 修改fault-policies.xml。
<!-- Step #3: Add your fault handler for mediator faults here: -->
<faultName xmlns:medns="http://schemas.oracle.com/mediator/faults" name="medns:mediatorFault">
<condition>
<action ref="my-mediator-fault-handler"/>
</condition>
</faultName>
<!-- Step #4: Add the Action definition for handling mediator fauls using custom java here:-->
<Action id="my-mediator-fault-handler">
<javaAction className="soatraining.faulthandling.MyFaultHandler"
defaultAction="ora-terminate" propertySet="myMediatorProps">
<returnValue value="OK" ref="ora-human-intervention"/>
</javaAction>
</Action>
<!-- Step #5: Add new property set for MyFaultHandler for logging Mediator faults here:-->
<propertySet name="myMediatorProps">
<property name="logFileName">mediator-faults.log</property>
<property name="logFileDir">c:\po\log</property>
</propertySet>
4.2 修改routePO mediator。
之所以要把“quantity < 1000”的路由从Sequential改成Parallel。
是因为Sequential表明Mediator的调用者和Mediator使用的是同一个Thread和Transaction Context,如果出现Mediator异常,异常将直接返回给调用者,而无法被Java Fault Handler捕捉到。
使用Parallel表明进入Mediator后,将启动一个新Thread和Transaction Context,如果出现Mediator异常,可以被Java Fault Handler捕捉到。
4.3 测试。
EM 中应该提示等待人工恢复,因为策略上设置的是“ora-human-intervention”。
因为我是Win7平台,所以没有测试,以后在Linux上再验证吧。
发表评论
-
SOA Suite 11g 开发指南之十四:使用BAM (Business Activity Monitor)
2012-08-06 18:40 699不知道为什么,原文作者这篇博文没有内容,所以只好自己加上,和前 ... -
SOA Suite 11g 开发指南之十三:使用SDO 访问与操作数据
2012-08-06 18:22 1021声明:该博文来自热爱JAVA,热爱生活。原文地址http:// ... -
SOA Suite 11g 开发指南之十二:使用EDN处理事件
2012-08-06 18:11 780. 声明:该博文来自热爱JAVA,热爱生活。原文地址http: ... -
SOA Suite 11g 开发指南之十一:使用OWSM配置安全策略
2012-08-06 18:07 1335声明:该博文来自热爱JAVA,热爱生活。原文地址http:// ... -
SOA Suite 11g 开发指南之九:为物流商配置JMS Queue
2012-08-03 09:34 832声明:该博文来自热爱JAVA,热爱生活。原文地址http:// ... -
SOA Suite 11g 开发指南之八:增加物流配送流程 Fulfillment
2012-08-03 09:31 745. 声明:该博文转自热 ... -
SOA Suite 11g 开发指南之七:增加 Business Rules
2012-08-03 09:28 678声明:该博文转自热爱java,热爱生活 原文地址http:// ... -
SOA Suite 11g 开发指南之六:增加人工工作流
2012-08-03 09:24 685声明:该博文转自热爱java,热爱生活 原文地址http:// ... -
SOA Suite 11g 开发指南之五:使用BPEL编排订单处理流程
2012-08-02 22:27 856声明:该博客转自热爱java,热爱生活,原文地址http:// ... -
SOA Suite 11g 开发指南之四:创建 Purchase Order Routing 服务
2012-08-02 22:14 782声明:该博文转自热爱java,热爱生活,原地址为http:// ... -
SOA Suite 11g 开发指南之三:创建 Credit Card Validation 服务
2012-08-02 22:12 824声明:该博文转自热爱java,热爱生活,原地址为http:// ... -
SOA Suite 11g 开发指南之二:实验环境准备
2012-08-02 22:08 888声明:该博文转自热爱j ... -
SOA Suite 11g 开发指南之一:场景介绍
2012-07-31 22:08 699声明:本博文来自http://maping930883.blo ...
相关推荐
Oracle SOA Suite 11g入门实例,详细介绍怎么进行SOA的开发入门
Oracle SOA Suite 11g Developer's Cookbook
Oracle SOA Suite 11g Handbook
Oracle SOA Suite 11g Handbook.pdf
用于和Oracle SOA Suite 11g 环境搭建手册(一) 一起搭建 Oracle SOA Suite 11g 的环境
Oracle SOA Suite 11g Developer's Guide
Oracle SOA Suite 11g 环境搭建手册(一)用于配置oralce soa 11g
ORACLE SOA SUITE 不错的书籍
Oracle SOA Suite 11g R1 Developer's Guide.pdf
Oracle SOA Suite 11g Developer's Cookbook 代码
[Packt Publishing] Oracle SOA Governance 11g 开发实践 (英文版) [Packt Publishing] Oracle SOA Governance 11g Implementation (E-Book) ☆ 图书概要:☆ Successfully implement SOA governance using ...
oracle soa suite 分,上下两部分。对soa的学习
oracle soa suite handbook best help for developers
Oracle SOA Suite 11g
This book was published by Packt Publishing. very good for oracle soa 11g administrator.
Oracle SOA Suite 12c Administrator's Guide 英文mobi 本资源转载自网络,如有侵权,请联系上传者或csdn删除 查看此书详细信息请在美国亚马逊官网搜索此书