- 浏览: 37589 次
- 性别:
- 来自: 北京
最新评论
声明:该博文来自热爱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 736不知道为什么,原文作者这篇博文没有内容,所以只好自己加上,和前 ... -
SOA Suite 11g 开发指南之十三:使用SDO 访问与操作数据
2012-08-06 18:22 1083声明:该博文来自热爱JAVA,热爱生活。原文地址http:// ... -
SOA Suite 11g 开发指南之十二:使用EDN处理事件
2012-08-06 18:11 823. 声明:该博文来自热爱JAVA,热爱生活。原文地址http: ... -
SOA Suite 11g 开发指南之十一:使用OWSM配置安全策略
2012-08-06 18:07 1360声明:该博文来自热爱JAVA,热爱生活。原文地址http:// ... -
SOA Suite 11g 开发指南之九:为物流商配置JMS Queue
2012-08-03 09:34 887声明:该博文来自热爱JAVA,热爱生活。原文地址http:// ... -
SOA Suite 11g 开发指南之八:增加物流配送流程 Fulfillment
2012-08-03 09:31 793. 声明:该博文转自热 ... -
SOA Suite 11g 开发指南之七:增加 Business Rules
2012-08-03 09:28 778声明:该博文转自热爱java,热爱生活 原文地址http:// ... -
SOA Suite 11g 开发指南之六:增加人工工作流
2012-08-03 09:24 725声明:该博文转自热爱java,热爱生活 原文地址http:// ... -
SOA Suite 11g 开发指南之五:使用BPEL编排订单处理流程
2012-08-02 22:27 916声明:该博客转自热爱java,热爱生活,原文地址http:// ... -
SOA Suite 11g 开发指南之四:创建 Purchase Order Routing 服务
2012-08-02 22:14 858声明:该博文转自热爱java,热爱生活,原地址为http:// ... -
SOA Suite 11g 开发指南之三:创建 Credit Card Validation 服务
2012-08-02 22:12 898声明:该博文转自热爱java,热爱生活,原地址为http:// ... -
SOA Suite 11g 开发指南之二:实验环境准备
2012-08-02 22:08 961声明:该博文转自热爱j ... -
SOA Suite 11g 开发指南之一:场景介绍
2012-07-31 22:08 755声明:本博文来自http://maping930883.blo ...
相关推荐
本入门实例将带领我们逐步了解并掌握如何在Oracle SOA Suite 11g环境中进行开发。 首先,我们需要理解SOA的核心概念。SOA是一种设计原则,它允许不同的应用程序通过共享可重用的服务进行通信。这些服务是自包含的,...
《Oracle SOA Suite 11g Developer's Cookbook》是一本专为Oracle SOA Suite开发者设计的实战指南,旨在帮助读者深入理解和应用Oracle SOA Suite 11g的各种功能和技术。Oracle SOA Suite作为一套全面的面向服务架构...
《Oracle SOA Suite 11g Developer's Guide》是一本旨在帮助开发者掌握Oracle SOA Suite 11g这一强大服务导向架构(Service-Oriented Architecture, SOA)解决方案的专业指南。本书由Antony Reynolds与Matt Wright...
《Oracle SOA Suite 11g Handbook》是针对Oracle企业级服务导向架构(Service-Oriented Architecture, SOA)解决方案的权威指南。Oracle SOA Suite是Oracle公司提供的一套全面集成的中间件平台,用于构建、部署和...
### Oracle SOA Suite 11g 环境搭建手册(二)——深入解析与实践指南 #### 一、WebLogic 11g 安装流程详解 在Oracle SOA Suite 11g环境中,WebLogic 11g作为基础的应用服务器平台起着至关重要的作用。以下是详细的...
《Oracle SOA Suite 11g R1 Developer's Guide》一书是针对Oracle SOA Suite 11g R1版本的全面开发指南,由Antony Reynolds和Matt Wright共同撰写,于2010年由Packt Publishing出版。本书旨在帮助开发者理解和掌握...
### Oracle SOA Suite 11g 环境搭建手册(一) #### 1. 前期准备 ##### 1.1. 硬件平台 为了顺利部署Oracle SOA Suite 11g,首先需要确保具备合适的硬件平台。最低要求如下: - 物理内存:1GB - 硬盘空间:20GB ...
Oracle SOA Suite是一款全面的企业服务总线(ESB)和业务流程管理(BPM)解决方案,由Oracle公司提供。它为企业提供了一整套工具和服务,用于构建、部署和管理面向服务的架构(SOA)。本篇文章将深入探讨Oracle SOA ...
### Oracle SOA Suite 11g R1 开发详解指南 #### 一、概述 《Oracle SOA Suite 11g R1 开发详解指南》是一本深入介绍Oracle SOA Suite 11g R1的书籍,作者为Antony Reynolds与Matt Wright。该书旨在帮助开发者了解...
1. **开发环境**:使用Oracle JDeveloper,一个全面的集成开发环境(IDE),支持SOA Suite组件的开发。 2. **生命周期管理**:通过Oracle Enterprise Manager提供,包括版本控制、测试、部署和更新等。 3. **测试与...
Oracle SOA Suite 11g Developer's Cookbook 代码
### Oracle SOA Suite 11g R1 (11.1.1.5.0) 快速入门指南 #### 一、Oracle SOA Suite 概述 Oracle SOA Suite 是一套全面且可热插拔的软件套件,用于构建、部署和服务导向架构(SOA)的管理。该套件的各个组件都...