我正在研究提供一种“热插拔”功能,用于在不同版本的drools规则之间切换。目标部署在WebSphere中,规则将全部在无状态会话bean中运行。理想情况下,我想预编译并将规则打包到一些离散文件中,并让Application Server确定新规则是否可用,并加载它们(跳过编译步骤)。
Drools文件表明这应该是可能的 - 但在机制方面却非常模糊。 Java EE方面的细节不是问题,但预编译令人头疼。
在发布一些帖子后,我把一些我认为可以解决问题的逻辑拉到了一起 - 以下编译规则文件并将其序列化为磁盘:
private void process(String outputFile, String inputFile) throws Exception {
String drl = fileToString(inputFile);
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem().write( "src/main/resources/r1.drl", drl );
ks.newKieBuilder( kfs ).buildAll();
ReleaseId releaseId = ks.getRepository().getDefaultReleaseId();
InternalKieModule kieModule = (InternalKieModule) ks.getRepository().getKieModule( releaseId );
byte[] jar = kieModule.getBytes();
serialize(jar, outputFile);
System.out.println("Class of InternalKieModule is " + kieModule.getClass());
}
以下内容已准备好创建KieSession:
private KieContainer getKbase(KieServices ks) throws Exception {
byte[] jar = deserialize(RULES_SER);
Resource jarRes = ks.getResources().newByteArrayResource(jar);
KieModule km = ks.getRepository().addKieModule(jarRes);
releaseId = km.getReleaseId();
KieContainer kc = ks.newKieContainer(km.getReleaseId());
return kc;
}
工作正常但是......我惊恐地发现我似乎需要除厨房水槽之外的所有东西才能实际运行它 - 只需不到50个独立的jar文件 - 占用16 MB并包括Ant罐子,10个Maven罐子,以及drools编译器jar,即使我不应该编译任何东西,我当然不会尝试使用Maven或Ant!在发行版中的67个Jar文件中,几乎所有文件都与Maven直接相关,而且很少(我从下面大约10到15的方法判断)实际上与规则运行时有关。
回到我用Drools 5构建的一个例子,几年前,我想出了以下代码来重新加载我使用知识库API单独编译的drl文件:
private KnowledgeBase readSavedKnowledgeBase() throws Exception {
byte[] serializedKb = (byte[]) deserialize(RULES_SER);
ByteArrayInputStream bais = new ByteArrayInputStream(serializedKb);
DroolsObjectInputStream ois = new DroolsObjectInputStream(bais);
KnowledgeBase kbase = (KnowledgeBase) ois.readObject();
ois.close();
return kbase;
}
这适用于6.1。我只需要9个罐子(我不需要编译器jar) - 而且我的运行时间相当合理5MB。缺点是Eclipse不满意,因为 KnowledgeBase 类现已弃用。
是否有人指出允许我使用非弃用类获得相同结果的方式,但没有Maven的所有包袱等我不想要或者不需要实际运行某些规则?
答案 0 :(得分:1)
用于构建的一些6.x代码:
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem();
FileInputStream fis = new FileInputStream( "sale/sale.drl" );
kfs.write( "src/main/resources/sale.drl",
ks.getResources().newInputStreamResource( fis ) );
KieBuilder kieBuilder = ks.newKieBuilder( kfs ).buildAll();
Results results = kieBuilder.getResults();
if( results.hasMessages( Message.Level.ERROR ) ){
System.out.println( results.getMessages() );
throw new IllegalStateException( "### errors ###" );
}
KieContainer kieContainer =
ks.newKieContainer( ks.getRepository().getDefaultReleaseId() );
// CEP - get the KIE related configuration container and set the EventProcessing (from default cloud) to Stream
KieBaseConfiguration config = ks.newKieBaseConfiguration();
config.setOption( EventProcessingOption.STREAM );
KieBase kieBase = kieContainer.newKieBase( config );
// KieSession kieSession = kieContainer.newKieSession();
KieSession kieSession = kieBase.newKieSession();
您可以序列化KieBase并重新启动以进行快速启动。我使用下面的CLASSPATH运行它进行各种测试,但是为了执行你不需要antlr,决策表,模板和(或许)其他人。
export CLASSPATH=".:$root/drools-core-${tag}.jar:$root/kie-api-${tag}.jar:$roo/kie-internal-${tag}.jar:$root/knowledge-internal-api-${tag}.jar:$root/drools-compiler-${tag}.jar:$root/antlr-runtime-3.5.jar:$root/ecj-4.3.1.jar:$root/mvel2-2.1.9.Final.jar:$root/drools-decisiontables-${tag}.jar:$root/drools-templates-${tag}.jar:$root/protobuf-java-2.5.0.jar:$root/slf4j-api-1.7.2.jar:$root/xstream-1.4.7.jar:$SLF4J"
对于序列化及其对应物使用通常的口头禅:
ObjectOutputStream out =
new ObjectOutputStream( new FileOutputStream( pkgPath ) );
out.writeObject( kieBase );
out.close();
//---------- In another program ---------------
ObjectInputStream in =
new ObjectInputStream( new FileInputStream( pkgPath ) );
@SuppressWarnings( "unchecked" )
KieBase kieBase = (KieBase)in.readObject();
in.close();
答案 1 :(得分:0)
如果你在类路径上有kie-ci,它只会带来Maven,删除它并且你不会有任何maven。但是你也没有任何依赖管理或pom分析 - 如果你不需要那些东西,你不需要maven来编译。如果没有kie-ci,它将回归到“轻量级”pom.xml解析器。您仍然可以通过编程方式为其提供所依赖的其他kiemodulies。