2012-07-03 1 views
2

Я работаю над системой, использующей drools для оценки определенных объектов. Однако эти объекты могут быть классов, загружаемых во время выполнения с использованием jodd. Я могу загрузить файл штраф с помощью следующей функции:Загрузка классов с jodd и использование их в drools

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); 
    } 
} 

Теперь давайте сказать, что я создал класс под названием шины и загрузил его с помощью функции выше. Есть ли способ, что я могу использовать класс шин в моем файле правил:

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

end 

Прямо сейчас, если я пытаюсь добавить это правило, я получаю ошибку говоря не в состоянии решить ObjectType Тир. Мое предположение состояло бы в том, что мне как-то понадобится импортировать Tire в правило, но я не совсем уверен, как это сделать.

+0

Я пробовал писать «import datatypes.Tire» в файле правил. (типы данных - это пакет, в котором должен быть класс шины). Теперь вместо того, чтобы говорить, не может разрешить шину, он говорит, что Tire не может быть разрешен для типа. Поэтому я интерпретирую это как то, что Tire решается на пакет вместо типа и поэтому не может быть импортирован. Почему это может быть? –

ответ

1

Не используйте Drools с версии 3, но попытайтесь помочь в любом случае. Когда вы загружаете класс таким образом (динамически, во время выполнения, независимо от того, используете ли вы, например, Class.forName() или Jodd), загруженное имя класса просто недоступно для явного использования в коде. Я считаю, что мы можем упростить вашу проблему с помощью следующего SUDO-кода, где вы первый загрузится класс, а затем попытаться использовать его имя:

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

Это, очевидно, не работает, так как тип шин не доступен во время компиляции : компилятор не знает, какой тип вы собираетесь загрузить во время выполнения.

Что будет работать, чтобы иметь шину, реализующую какой-либо интерфейс (например, VehiclePart). Итак, вы можете использовать следующий Судо-код:

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

Тогда, возможно, вы можете построить свои Drools правило через интерфейс VehiclePart и имущества getPartName().

Добавление

выше имеют смысл только тогда, когда интерфейс охватывает все свойства динамически загружаемого класса. В большинстве случаев это недействительное решение: динамически загруженные классы просто не разделяют свойства. Итак, вот еще один подход.

Вместо использования явной загрузки классов эту проблему можно решить, «расширив» путь класса classloader. Будьте осторожны, это хак!

В Джодд, есть метод: ClassLoaderUtil.addFileToClassPath(), который может добавить файл или путь к загрузчику классов в среде выполнения. Итак, вот шаги, которые сработали для меня:

1) Поместите все динамически созданные классы в некоторую корневую папку с учетом их пакетов. Например, допустим, мы хотим использовать класс jodd.samples.TestBean, который имеет два свойства: номер (int) и значение (строка). Затем нам нужно поставить этот класс в папку root/jodd/samples.

2) После построения всех динамических классов, расширить путь загрузчиков классов:

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

3) класс нагрузки и создать его перед созданием KnowledgeBuilder:

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

4) На данный момент вы можете использовать BeanUtils (от Джодда, например :) для управления свойствами экземпляра testBean

5) Создайте материал Drools и добавьте вставку testBean в сеанс:

knowledgeSession.insert(testBean); 

6) Используйте его в правиле файла:

import jodd.samples.TestBean; 

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

Это работает для меня. Обратите внимание, что на шаге 2 вы можете попробовать использовать другой загрузчик классов, но вам может понадобиться передать его в KnowledgeBuilderFactory через KnowledgeBuilderConfiguration (то есть PackageBuilderConfiguration).

Другое решение

Другим решением является просто скопировать все свойства объекта на карте, и иметь дело с картой в файлах правил. Таким образом, вы можете использовать что-то вроде этого на шаге 4:

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

, а затем (шаг # 5) добавить карту в Drools контекст вместо экземпляра компонента. В этом случае было бы лучше использовать метод defineClass() для явного определения каждого класса.

+0

спасибо! У нас уже есть интерфейс под названием DataType, поэтому ваше решение должно быть очень простым в реализации. Большое спасибо! –

+0

Я пробовал ваше решение, и я получил следующую ошибку. Я определил класс в предложении when, это правильно или должно быть где-то еще? [12,7]: [ERR 102] Строка 12: 7 несоответствующий вход «tireClass» в правиле «Эксплуатация шин» [0,0]: Parser возвратил нулевой пакет –

+0

oops Я только понял, что вы сказали, что sudo code, конечно, не работает , извините –