ヘッダーをスキップ
Oracle® Fusion Middleware Oracle Business Rulesユーザーズ・ガイド
11gリリース1 (11.1.1.7)
B55917-06
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

C Oracle Business Rulesに関するよくある質問

この付録では、Oracle Business Rulesに関するよくある質問を紹介します。

C.1 JavaオブジェクトをファクトとしてアサートしてからModifyアクションを使用せずに変更すると、ルールが起動しないのはなぜですか。

Javaオブジェクトをアサートした後でModifyアクションを使用せずに変更した場合は、オブジェクトをRules Engineに再アサートする必要があります。したがって、変更したJavaオブジェクトに関連付けられたルールが起動しない場合は、Rules Engineでルール条件が再評価されておらず、ルールもアクティブ化されていないことを意味します。このため、Modifyアクションを使用せずにJavaオブジェクトを変更した場合には、オブジェクトをRules Engineに再アサートする必要があります。

C.2 Oracle Business Rules RL LanguageとJavaの相違はなんですか。

Oracle Business Rules RL LanguageとJavaの相違の詳細は、『Oracle Fusion Middleware Oracle Business Rulesランゲージ・リファレンス・ガイド』の付録Aを参照してください。

C.3 RuleSessionでは並行性と同期化はどのように処理されますか。

Oracle Business Rules RuleSessionオブジェクトに対するメソッド・コールは、複数のスレッドによるコールによって、RuleSessionレベルでの例外が発生しないようにスレッド・セーフになっています。ただし、メソッドの実行に排他性やトランザクション保証はありません。Rules Engineの最低レベルのrunメソッドは同期化されるため、共有RuleSessionを持つ2つのスレッドは同時にrunを実行できません。runへの一方のコールは、もう一方のコールが終了するまで待機する必要があります。

Oracle Business Rules関数は、デフォルトでは同期化されません。Javaメソッド同様、Oracle Business Rules関数は並行して実行可能であり、プログラマは同期化されたブロックを使用して共有データ(たとえば、結果データを含むHashMap)へのアクセスを保護する必要があります。

トランザクションのような形式で実行する必要があるアクション・セットでは、共有オブジェクトに関する同期化が必要になります。RuleSessionオブジェクトに関する同期化はできません。RuleSessionメソッドのコール時にスローされる例外で、RuleSessionオブジェクトの破棄が必要になる場合があるからです。

RuleSessionオブジェクトをOracle Business Rulesで使用するほとんどの場合、各スレッドまたはサーブレット・インスタンスは、ローカルのRuleSessionオブジェクトを作成して使用する必要があります。この使用パターンは、この方法でJDBC接続を使用した場合とおおよそ似ています。

次の例は、共有RuleSessionオブジェクトを使用する方法を示しています。

Thread-1が次のものを含む場合:

ruleSession.callFunctionWithArgument("assert", singleFact1);
ruleSession.callFunctionWithArgument("assert", singleFact2);

Thread-2が次のものを含む場合:

ruleSession.callFunction("run");
ruleSession.callFunction("clear");

この場合、2つのスレッドの実行は、例C-1に示すように進むことがあります。

例C-1 Oracle Business Rulesにおける共有RuleSessionオブジェクトの使用

Thread-1:  ruleSession.callFunctionWithArgument("assert", singleFact1);
Thread-2:  ruleSession.callFunction("run");
Thread-2:  ruleSession.callFunction("clear"); 
Thread-1:  ruleSession.callFunctionWithArgument("assert", singleFact2); 

例C-1では、Thread-1がアサートした2つのファクトの両方が、runへのコール中にRuleSessionに存在することはありません。また、1つのスレッドのみがrunメソッドをコールすることに注意してください。共有RuleSessionで複数のスレッドからrunをコールできるデザインを使用すると、非常に見つけにくい不具合が作成される可能性があり、パフォーマンス上の利点はありません。

共有RuleSessionオブジェクトに対するすべてのアクセスを同期化して、意図した動作を保証する必要があります。ただし、RuleSessionインスタンスが例外をスローして回復不能になることがあるため、このオブジェクトを同期化オブジェクトとしては使用しないでください。かわりに、別の共有オブジェクトを同期点として使用します。

候補としては、共有サーバー・プロセス・プロデューサが考えられます。RuleSession用のコンシューマ・モデルです。このモデルでは、複数のスレッドが共有のRuleSessionにファクトをアサートし、1つのスレッドが定期的にrunをコールし、結果を読み取って出力します。これにより、2つのコード・セグメントが必ずシリアルに実行され、混在できなくなるので、スレッドの競合が発生しなくなります。例C-2例C-3例C-4の共有オブジェクト、プロデューサ・コード、コンシューマ・コードを使用したコード例を参照してください。

例C-2 RuleSessionの共有オブジェクト

RuleSession ruleSession;
Object ruleSessionLock = new Object();

例C-3 RuleSessionのプロデューサ・コード

public String addFacts(FactTypeA fa, FactTypeB fb, FactTypeC fc){
   String status = "";
   synchronized(ruleSessionLock){
     try {
       ruleSession.callFunctionWithArgument("assert", fa);
       ruleSession.callFunctionWithArgument("assert", fb);
       status = "success";
     } catch (Exception e) { 
       // a method that creates a new RuleSession loads it with rules
       initializeRuleSession(); 
       status = "failure";
     }
     return status;
}

例C-4 RuleSessionのプロデューサ・コード

public List exec(){
  synchronized(ruleSessionLock){
    try {
      ruleSession.callFunction("run");
      List results = (List)ruleSession.callFunction("getResults");
      ruleSession.callFunction("clearResults");
      return results;
    }  catch (Exception e) { 
      // a method that creates a new RuleSession loads it with rules
      initializeRuleSession();
      return null;
    }
  }
}

注意:

複数のスレッドがRuleSessionオブジェクトを共有している場合、複数のスレッドがrunメソッドをコールすると、非常に見つけにくい不具合が作成される可能性があり、パフォーマンス上の利点はありません。


C.4 自己結合を正しく表現するにはどうすればよいですか。

ファクトを使用した場合、Oracle RLのランタイム動作で極端な結果が生成されることがあります。

例C-5のOracle RLコードについて考えます。

例C-5 ファクトFを使用した自己結合

class F {int i; }; 
rule r1 { 
  if (fact F f1 && fact F f2) { 
    println("Results: " + f1.i + ", " + f2.i); 
  }
} 
assert(new F(i:1)); 
assert(new F(i:2)); 
run(); 

例C-5で行がいくつ出力されるか考えます。f1f2の両方については、同じファクト・インスタンスが一致できるため、答えは4行です。

したがって、例C-5では次の出力が生成されます。

Results: 2, 2 
Results: 2, 1 
Results: 1, 2 
Results: 1, 1 

3番目のFのある同じ例を使用すると(たとえば、assert(new F(i:3));)、9つの行が出力されます。また同時に、3番目の語句&& fact F F3が追加されると、27の行が出力されます。

個別のファクトについてすべての組合せおよび順序を見つけようとしている場合は、例C-6に示すように、テスト内に追加語句が必要になります。

例C-6 ファクトFのすべての組合せの検索

rule r1 { 
  if (fact F F1 && fact F F2 && F1 != F2) { 
    println("Results: " + F1.i + ", " + F2.i); 
  }
} 

例C-6のコードでは、次の出力が生成されます。

Results: 2, 1 
Results: 1, 2 

ファクトのすべての組合せを検出する最も簡単な方法は、最速ではなく順序も不同ですが、例C-7に示したコードを使用するものです。

例C-7 ファクトFの組合せの検索

rule r1 { 
  if (fact F F1 && fact F F2 && id(F1) < id(F2)) { 
    println("Results: " + F1.i + ", " + F2.i); 
  }
} 

例C-7に示した関数id()をテスト・パターンで実行すると直接比較よりも時間がかかるため、各オブジェクトで一意の値に対してテストするのが最も速い方法になります。たとえば、整数値プロパティoidを、クラスの各インスタンスの固有値を割り当てられたクラスに追加できます。

例C-8は、oid値を使用する同じルールを示しています。

例C-8 高速の完全比較

rule r1 { 
  if (fact F F1 && fact F F2 && F1.oid < F2.oid) { 
    println("Results: " + F1.i + ", " + F2.i); 
  }
} 

この問題は、例C-9に示した関数を使用して、Oracle Rules Engineからすべての重複するファクトを削除しようとした場合にも生じることがあります。

例C-9 重複するファクトを取り消す不正な例

rule rRemoveDups { 
  if (fact F F1 && fact F F2 && F1.i == F2.i) { 
    retract(F2); 
  } 
} 

ただしこのルールでは、重複するファクトだけでなく、タイプFのすべてのファクトが削除されます。F1F2が同じファクト・インスタンスの可能性があるからです。例C-10に、このルールの正しいバージョンを示します。

例C-10 重複するファクトを取り消す修正された例

rule rRemoveDups { 
  if (fact F F1 && fact F F2 && F1 != F2 && F1.i == F2.i) { 
    retract(F2); 
  } 
}

C.5 Oracle Business Rulesではプロパティ変更リスナーをどのように使用しますか。

Oracle Rules Engineは、Java PropertyChangeListener設計パターンをサポートしています。これにより、PropertyChangeSupportクラスを使用するJavaファクトのインスタンスは、プロパティ値が変更されたときに自動的にOracle Rules Engineに通知できます。Javaファクトは、Oracle Rules Engineで使用するこのパターンの実装に必須ではありません。

通常、Oracle Rules Engineに対して以前アサートされたJavaオブジェクトのプロパティ値が変更された場合は、新しいプロパティ値でルールを再評価するため、オブジェクトを再アサートする必要があります。PropertyChangeEventを起動するプロパティの場合、これらのプロパティの値を変更すると、値が変更されて、ファクトがOracle Rules Engineに対して再アサートされます。

PropertyChangeListener設計パターンをクラスに実装する手順は次のとおりです。

  1. このパッケージをクラスにインポートします。

    import java.beans.PropertyChangeSupport;
    
  2. プライベート・メンバー変数をクラスに追加します。

    private PropertyChangeSupport m_pcs = null;
    
  3. コンストラクタで、PropertyChangeSupportオブジェクトを作成します。

    m_pcs = new PropertyChangeSupport(this);
    
  4. 次の各setterに対して、firePropertyChangeへのコールを追加します。

    public void setName( String name ){
        String oldVal =  m_name;
        m_name = name;
        m_pcs.firePropertyChange( "name", oldVal, m_name );
    }
    
  5. addPropertyChangeListenerメソッドを実装します(m_pcsに委任します)。

    public void addPropertyChangeListener(PropertyChangeListener pcl){
        m_pcs.addPropertyChangeListener( pcl );
    }
    
  6. removePropertyChangeListenerメソッドを実装します(m_pcsに委任します)。

    public removePropertyChangeListener(PropertyChangeListener pcl){
        m_pcs.removePropertyChangeListener( pcl );
    }
    

アプリケーションの設計について、変更されたオブジェクトを常に明示的に再アサートするか、またはPropertyChangeListener設計パターンを実装するかを決定する場合は、次の点を考慮してください。

C.6 Oracle Business Rulesでデシジョン・サービスを使用する場合にどのような制限がありますか。

BPELプロセスでBusiness Rulesを使用する場合、次のような制限があります。

他の制限は、付録D「デシジョン・サービスの入力と出力の要素タイプはどのように制限されますか。」を参照してください。

XMLファクト・タイプの参照可能オプションの設定の詳細は、第3.2項「XMLファクトの使用」を参照してください。

C.7 ルールにJavaコードを挿入するにはどうすればよいですか。

実際、Javaコードをルールに挿入することはありません。ただし、ルール条件またはアクションからJavaメソッドを起動できます。

C.8 BPELでデシジョン・サービスにJavaベース・ファクトを使用することはできますか。

Oracle BPEL PMが起動できるのは、デシジョン・サービスとして公開されたデシジョン関数のみであるため、デシジョン関数の入力および出力はXMLファクト・タイプである必要があります。

入力XMLファクトをJavaファクトに変換する場合は、Javaファクト・タイプを使用する既存のルールセットまたはデシジョン関数を使用できます。たとえば、convertFromXMLというルールセットになんらかのルールを作成し、このルールセットをデシジョン関数ルールフロー内でJavaルールセットの前に挿入できます。同様に、Javaファクトを出力XMLファクトに変換するルールセットを作成し、このルールセットをデシジョン関数ルールフロー内でJavaルールセットの後に挿入できます。

また、ルールでJavaファクト・タイプのプロパティのみを使用し、メソッドやフィールドを使用しない場合は、次の手順でJavaファクト・タイプをXMLファクト・タイプで置換できます。

  1. Javaファクト・タイプを削除します(最初にファクト・タイプおよびプロパティの別名を慎重にメモしてください)。

  2. 類似するXMLファクト・タイプをインポートし、そのファクト・タイプおよびプロパティの別名を、削除したJavaファクト・タイプおよびプロパティと同じになるように編集します。

C.9 BPELデシジョン・サービスでデバッグ機能を有効化するにはどうすればよいですか。

BPELデシジョン・サービスに対するルールセット実行中のデバッグ出力を有効化するには、SOAルール・ロガーを有効化します。SOAルール・ロガーがTRACEレベルに設定されていると、watchAllの出力がSOA診断ログに記録されます。Fusion Middleware Controlコンソールを使用してロギング・レベルを変更した場合、指定のレベルを使用するようにアプリケーションを再デプロイする必要はありません。

SOA oracle.soa.service.rulesおよびoracle.soa.services.rules.obrtraceロガーの詳細は、『Oracle Fusion Middleware Oracle SOA SuiteおよびOracle Business Process Management Suite管理者ガイド』を参照してください。

C.10 Oracle Business Rulesでバージョニングをサポートするにはどうすればよいですか。

Oracle Business Rulesでは、バージョニングが次の2つの方法でサポートされています。

注意: サーバー・アプリケーションは、ディクショナリ変更がMDS内で参照可能になると、その変更にレスポンスできます。ルール・サービス・エンジン(デシジョン・サービス)では、これが自動的に実行されます。非SCAアプリケーションの場合、これはRuleRepositoryインタフェースを使用して実行できます。この時点では、ドラフト・バージョンをサポートするには、MDSのサンドボックス機能を使用します。Oracle Business RulesのRuleRepositoryインタフェースでは、これがサポートされています。

C.11 ルールおよびデシジョン表で優先度を使用する場合、優先度の順序はどうなりますか。

ルールおよびデシジョン表の優先度は最高から最低までで、優先度の高いルールまたはデシジョン表が先に実行されます。たとえば、優先度1から4のルールを作成すると、各ルールは4、3、2、1という実行優先度の順に実行されます。ルール・デザイナを使用して、事前定義済の名前が付いた優先度のリストから選択するか、正または負の整数を入力して独自の優先度レベルを指定できます。デフォルトの優先度はmedium(整数値0)です。詳細は、第4.5.5項「ルールの優先度の設定方法」を参照してください。

ただし、ルールの純粋な宣言モデルが損なわれるため、できるだけ優先度の使用を避ける必要があることに注意してください。多数の優先度を使用していることに気づいた場合の最善策は、通常、競合を避けるようにルールおよびテストを再構築するか、特定の順序で実行することを意図する場合はルールフローを使用してルールを複数のルールセットに分割することです。競合は、ルールセット内の複数のルールが起動可能な場合に発生します。たとえば、gold customerルールでは$1000を超える支払がある顧客をgold customerとし、silver customerルールでは$500を超える支払がある顧客をsilver customerとする場合、顧客が$1100を支払うと競合が発生します。$500から$1000の間の支払の顧客をテストする場合、ルールに優先度を設定するよりも、silver customerルールを変更する方が明解です。こうした競合分析や競合回避は、デシジョン表を使用すると非常に簡単にできます。デシジョン表の詳細は、第5章「デシジョン表の使用」を参照してください。

ルールセットの順序を変更するには、ルールフローを使用します(これはルールセット・スタックです)。ルールセット・スタックの使用方法の詳細は、『Oracle Fusion Middleware Oracle Business Rulesランゲージ・リファレンス・ガイド』を参照してください。

C.12 xsd:string入力済要素を持つXMLスキーマをタイプJAXBElementとしてインポートするのはなぜですか。

JAXB 2.0仕様によると、minOccurs="0"およびnillable="true"の属性がある要素のデフォルトの型マッピングは、JAXBElement<T>です。このTは、その要素に対して定義された型のデフォルト・マッピングです。たとえば、xsd:stringJAXBElement<String>に、xsd:intJAXBElement<Integer>に、xsd:integerJAXBElement<BigInteger>にマップされます。これは、nillable="true"が、ドキュメント内でminOccurs=0を使用して定義されていない(定義する必要はない)要素と、定義されているがnil="true"という属性を持つ要素の間のセマンティクスの相違が定義済であることを意味しているからです。これはわずかな相違で、不明な値と「値なし」として認識される値との相違を定義するためによく使用されます。

ルールでJAXBElementタイプのプロパティを使用するには、そのプロパティが非NULLかどうかを最初にチェックする必要があります。その後、"value"プロパティまたはgetValue()メソッドを使用して、基礎となるタイプの値を取得できます。

fact FactType1 &&
    FactType1.prop1 != null &&
    FactType1.prop1.value == "abc"

または、nillable要素がタイプJAXBElement<T>ではなくタイプTにマップされるように、カスタマイズしたJAXBバインディングを定義できます。ただし、これでは存在しない要素およびnil要素の違いを判別できなくなるため、無駄な変換です。この場合、nillable属性はあまり役立ちませんが、JavaでObjectタイプのフィールドがデフォルトでNULLに初期化されたり、明示的にNULLに初期化できるのと同様に、文書では要素をnilとして明示的に定義できます。

そのためには複数の方法があります。いずれの場合も、これらの属性を最上位レベルのxsd:schema要素の開始タグに追加します。

xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="2.0"
  1. すべてのプロパティでバインディングを使用するように指定するには、これをxsd:schemaの開始タグ内の先頭に追加します。

    <xsd:annotation>
        <xsd:appinfo>
            <jaxb:globalBindings generateElementProperty="false"/>
        </xsd:appinfo>
    </xsd:annotation>
    
  2. 特定のプロパティでのみバインディングを使用するように指定するには、必要な各要素に次のような注釈を追加します。

    <xsd:element name="stringElement2" type="xsd:string" minOccurs="0" nillable="true">
        <xsd:annotation>
            <xsd:appinfo>
                 <jaxb:property generateElementProperty="false" />
            </xsd:appinfo>
        </xsd:annotation>
    </xsd:element>
    
  3. 外部カスタマイズ・ファイルに定義を追加し、スキーマをデータ・モデルに追加する際に引数として渡します。この方法は、SchemaBrowserクラスをプログラムでコールし、ルール・デザイナで公開しない場合にのみ可能です。

C.13 Javaクラスに加えた変更がデータ・モデルに反映されないのはなぜですか。

SCA-INF/classesディレクトリでコンパイルされたクラスはインポートしないでください。このディレクトリのクラスを変更すると、データ・モデルにリロードできなくなります。

C.14 Rules SDKを使用して式にNULLを含めるにはどうすればよいですか。

次のRules SDKコードを使用すると、null値を含めることができます。

SimpleTest test = pattern.getSimpleTestTable().add();
test.getLeft().setValue(attr);
test.setOperator(Util.TESTOP_NE);
test.getRight().setValue("null");

C.15 ディクショナリを格納するためのリポジトリとしてWebDAVがサポートされていますか。

Oracle Fusion Middleware 11gリリース1 (11.1.1)のOracle Business Rulesでは、ディクショナリを格納するためにWebDAV (Web Distributed Authoring and Versioning)リポジトリはサポートされていません。Oracle Business Rulesでは、MDS(ファイルまたはデータベースを使用)リポジトリを使用したディクショナリの格納がサポートされています。

C.16 ルール・デザイナによるソース・コード制御システムの使用

ルール・デザイナと、CVSまたはSubversionなどのソース制御システムを使用する場合には、特別な注意事項があります。ソース・コード制御システムとルール・デザイナを使用する場合には、プロジェクト内のルール・ディクショナリ・ファイルがテキスト・ファイルではなく、バイナリ・ファイルとして認識されるように指定する必要があります。ルール・ディクショナリ・ファイルはXML文書で、デフォルトで、ソース・コード制御システムはこれらのファイルをテキスト・ファイルとして処理します。しかし、ルール・ディクショナリ・ファイルには、セマンティク構造が含まれているので、これらのファイルをマージすることはできません。ルール・ディクショナリ・ファイルがテキスト・ファイルとして処理され、変更された場合、ソース制御システムはトリビアル・マージによってこのファイルのマージを試行します。トリビアル・マージを使用すると、セマンティクスの無効なディクショナリ・ファイルが作成され、RuleDictionaryオブジェクトにアンマーシャリングできなくなります。

したがって、ソース・コード制御システムとルール・ディクショナリ・ファイル(.rulesファイル)を使用する場合には、必ずソース・コード制御システムがこれらのファイルをバイナリ・ファイルとして処理するように指定する必要があります。このシステムがディクショナリ・ファイルをバイナリ・ファイルとして処理するように指定するには、いくつかの構成オプションを設定する必要があります。たとえば、Subversionソース・コード制御システムでは、svn:mime-typeファイル・プロパティを使用してMIMEタイプを設定できます。詳細は次の項を参照してください。

http://svnbook.red-bean.com/nightly/en/svn.advanced.props.file-portability.html#svn.advanced.props.special.mime-type

バイナリ・ファイル・タイプを指定するためのソース・コード制御システム・オプションを設定すると、ソース・コード制御システム(tortoiseSVNなど)が、ルール・ディクショナリ・ファイルをバイナリ・ファイルとして正しく処理できるようになります。