2

私は、droolsを使用して特定のオブジェクトを評価するシステムに取り組んでいます。ただし、これらのオブジェクトは、joddを使用して実行時にロードされるクラスのものにすることができます。次の関数を使用して、ファイルを正常にロードできます。

 public static void loadClassFile(File file) {
    try {
        // use Jodd ClassLoaderUtil to load class into the current ClassLoader
        ClassLoaderUtil.defineClass(getBytesFromFile(file));
    } catch (IOException e) {
        exceptionLog(LOG_ERROR, getInstance(), e);
    }
 }

ここで、Tireというクラスを作成し、上記の関数を使用してロードしたとします。ルールファイルでTireクラスを使用する方法はありますか?

rule "Tire Operational"
when
    $t: Tire(pressure == 30)
then

end

現在、このルールを追加しようとすると、ObjectTypeTireを解決できないというエラーが表示されます。ルールにタイヤをインポートする必要があると思いますが、どうすればよいかわかりません。

4

1 に答える 1

1

バージョン 3 以降 Drools を使用していませんが、いずれにせよ助けようとします。この方法でクラスをロードすると (たとえば、Class.forName() または Jodd を使用するかどうかに関係なく、実行時に動的に)、ロードされたクラス名をコードで明示的に使用することはできません。最初にクラスをロードしてからその名前を使用しようとする次の sudo コードを使用して、問題を単純化できると思います。

defineClass('Tire.class');
Tire tire = new Tire();

Tire 型はコンパイル時に利用できないため、これは明らかに機能しません。コンパイラは、実行中にロードする型を認識していません。

うまくいくのは、Tire に何らかのインターフェース (VehiclePart など) を実装させることです。したがって、次の sudo コードを使用できます。

Class tireClass = defineClass('Tire.class');
VehiclePart tire = tireClass.newInstance();
System.out.println(tire.getPartName()); // prints 'tire' for example

次に、VehiclePart インターフェイスと getPartName() プロパティに対して Drools ルールを構築できます。

補遺

上記は、インターフェイスが動的にロードされたクラスのすべてのプロパティをカバーする場合にのみ意味があります。ほとんどの場合、これは有効な解決策ではありません。動的にロードされたクラスは単にプロパティを共有しません。したがって、ここに別のアプローチがあります。

この問題は、明示的なクラス ローディングを使用する代わりに、クラスローダーのクラス パスを「拡張」することで解決できます。注意してください、これはハックです!

Jodd には、実行時にファイルまたはパスをクラスローダーに追加できるClassLoaderUtil.addFileToClassPath()メソッドがあります。だからここに私のために働いたステップがあります:

1) 動的に作成されたすべてのクラスを、それらのパッケージに関していくつかのルート フォルダーに配置します。たとえば、数値(int) と(string)の2 つのプロパティを持つjodd.samples.TestBeanクラスを使用するとします。次に、このクラスをroot/jodd/samplesフォルダーに配置する必要があります。

2) すべての動的クラスを構築した後、classloaders パスを拡張します。

ClassLoaderUtil.addFileToClassPath("root", ClassLoader.getSystemClassLoader());

3) クラスをロードして、KnowledgeBuilder を作成する前に作成します。

Class testBeanClass = Class.forName("jodd.samples.TestBean");
Object testBean = testBeanClass.newInstance();

4) この時点で、BeanUtils (Jodd などから) を使用して、testBean インスタンスのプロパティを操作できます。

5) Drools を作成し、insert testBean をセッションに追加します。

knowledgeSession.insert(testBean);

6) ルール ファイルで使用します。

import jodd.samples.TestBean;

rule "xxx"
    when
    $t: TestBean(number == 173)
then
    System.out.println("!!!");
end

これは私にとってはうまくいきました。ステップ 2 では、別のクラスローダーを使用してみることができますが、KnowledgeBuilderConfiguration (つまり PackageBuilderConfiguration) を介して KnowledgeBuilderFactory に渡す必要がある場合があることに注意してください。

別の解決策

もう 1 つの解決策は、すべてのオブジェクト プロパティをマップに単純にコピーし、ルール ファイルでマップを処理することです。したがって、ステップ #4 で次のようなものを使用できます。

Map map = new HashMap();
BeanTool.copy(testBean, map);

その後 (ステップ #5) Bean インスタンスの代わりに Drools コンテキストにマップを追加します。この場合、defineClass()メソッドを使用して各クラスを明示的に定義する方がよいでしょう。

于 2012-07-06T21:43:03.710 に答える