从胖罐子里运行Drools Kie项目



我正试图从一个使用sbt assembly生成的胖罐子中运行一个基于drools(和KieServices)的项目。

[main] INFO org.drools.compiler.kie.builder.impl.ClasspathKieProject - Found kmodule: jar:file:/.../myJar.jar!/META-INF/kmodule.xml
[main] ERROR org.drools.compiler.kie.builder.impl.ClasspathKieProject - Unable to build index of kmodule.xml url=jar:file:/.../myJar.jar/META-INF/kmodule.xml
You're trying to perform a xml related operation without the necessary xml support for drools. Please add the module org.drools:drools-xml-support to your classpath.
[main] ERROR org.drools.compiler.kie.builder.impl.KieContainerImpl - Unknown KieSession name: DroolDummyKS

此错误由以下代码触发,最后一行具体说明:

val kieServices: KieServices = KieServices.Factory.get
val kieContainer: KieContainer = kieServices.getKieClasspathContainer
// Apply the correct kie session from the ./resources/META-INF/kmodule.xml configuration
val kieSession: KieSession = kieContainer.newKieSession("DroolDummyKS")

项目是Scala SBT项目(Java 11作为编译器)

我无法复制Unable to build index of kmodule.xml。只有kieContainer.newKieSession("DroolDummyKS")为汇编jar(java -jar myJar.jar)返回null,而sbt run则返回KieSession[0]

注意,它写在你的错误:

请将模块org.drools:drools-xml-support添加到类路径中

build.sbt:中做两件事

  • 添加到libraryDependencies

    "org.drools" % "drools-xml-support" % "8.31.1.Final" 
    

  • 在汇编策略中忽略kmodule.xml(这样kmodule.xml就包含在汇编jar中),例如使用singleOrError(不确定级联对xml是否有意义,与服务文件相反,我们要确保它是您的kmodule.xml,否则它会抛出)

    assembly / assemblyMergeStrategy := {
    case PathList("META-INF", "services", xs@_*) => MergeStrategy.concat
    case PathList("META-INF", "kmodule.xml") => MergeStrategy.singleOrError
    case PathList("META-INF", xs@_*) => MergeStrategy.discard
    case _ => MergeStrategy.first
    }
    

更新使用

assembly / assemblyMergeStrategy := {
case _ => MergeStrategy.singleOrError
}

您可以检查哪些文件有重复项。

您应该添加依赖项"org.drools" % "drools-xml-support" % "8.31.1.Final",正如我之前建议的那样。否则,即使对于CCD_ 17也存在NPE我看到你在更新中添加了它

您应该删除文件src/main/resources/META-INF/services/org.kie.api.KieServices。无论如何,它存在于依赖drools-compiler-8.31.1.Final.jar中。

尝试忽略尽可能少的的策略

assembly / assemblyMergeStrategy := {
case xs if xs.endsWith("LICENSE") => MergeStrategy.discard
case xs if xs.endsWith("LICENSE.txt") => MergeStrategy.discard
case xs if xs.endsWith("INDEX.LIST") => MergeStrategy.discard
case xs if xs.endsWith("MANIFEST.MF") => MergeStrategy.discard
case xs if xs.endsWith("NOTICE") => MergeStrategy.discard
case xs if xs.endsWith("NOTICE.txt") => MergeStrategy.discard
case xs if xs.endsWith("module-info.class") => MergeStrategy.discard
case PathList("META-INF", "services", "org.apache.poi.sl.draw.ImageRenderer") => MergeStrategy.filterDistinctLines
case PathList("META-INF", "services", "org.apache.poi.ss.usermodel.WorkbookProvider") => MergeStrategy.filterDistinctLines
case PathList("META-INF", "services", "org.apache.poi.extractor.ExtractorProvider") => MergeStrategy.filterDistinctLines
case PathList("META-INF", "services", "org.drools.wiring.api.ComponentsSupplier") => MergeStrategy.filterDistinctLines
case _ => MergeStrategy.singleOrError
}

然后应解决重复问题。

filterDistinctLines类似于concat,只是没有添加相同的行。

该策略可以简化

assembly / assemblyMergeStrategy := {
case xs if Seq(
"LICENSE",
"LICENSE.txt",
"INDEX.LIST",
"MANIFEST.MF",
"NOTICE",
"NOTICE.txt",
"module-info.class"
).exists(xs.endsWith) => MergeStrategy.discard
case PathList("META-INF", "services", xs@_*) => MergeStrategy.filterDistinctLines
case _ => MergeStrategy.singleOrError
}

更新2。我查找了最新NPE 的原因

Exception in thread "main" java.lang.NullPointerException: 
Cannot invoke 
"org.drools.compiler.compiler.Dialect.getId()"
because the return value of
"org.drools.compiler.rule.builder.RuleBuildContext.getDialect()"
is null

事实证明,这个东西在一个依赖项的文件META-INF/kie.default.properties.conf中。因此,额外忽略就足够了

assembly / assemblyMergeStrategy := {
case x if x.endsWith("module-info.class") => MergeStrategy.discard
case PathList("META-INF", "services", xs@_*) => MergeStrategy.concat
case PathList("META-INF", "kmodule.xml") => MergeStrategy.singleOrError
case PathList("META-INF", "kie.default.properties.conf") => MergeStrategy.singleOrError
case PathList("META-INF", xs@_*) => MergeStrategy.discard
case _ => MergeStrategy.first
}

但我们的主要结论应该是,忽略整个META-INF可能是危险的。可能还有一些其他文件对某些依赖关系很重要。也许现在没有NPE,但有些问题可能会推迟。

事实证明,默认的组装策略

assembly / assemblyMergeStrategy := MergeStrategy.defaultMergeStrategy

assembly / assemblyMergeStrategy := {
case x =>
val oldStrategy = (ThisBuild / assemblyMergeStrategy).value
oldStrategy(x)
}

或(见此处)

val defaultMergeStrategy: String => MergeStrategy = {
case x if Assembly.isConfigFile(x) =>
MergeStrategy.concat
case PathList(ps @ _*) if Assembly.isReadme(ps.last) || Assembly.isLicenseFile(ps.last) =>
MergeStrategy.rename
case PathList("META-INF", xs @ _*) =>
(xs map {_.toLowerCase}) match {
case ("manifest.mf" :: Nil) | ("index.list" :: Nil) | ("dependencies" :: Nil) =>
MergeStrategy.discard
case ps @ (x :: xs) if ps.last.endsWith(".sf") || ps.last.endsWith(".dsa") =>
MergeStrategy.discard
case "plexus" :: xs =>
MergeStrategy.discard
case "services" :: xs =>
MergeStrategy.filterDistinctLines
case ("spring.schemas" :: Nil) | ("spring.handlers" :: Nil) =>
MergeStrategy.filterDistinctLines
case _ => MergeStrategy.deduplicate
}
case _ => MergeStrategy.deduplicate
}

这项工作做得很好。您只需要忽略另外的文件module-info.class。所以你可以更喜欢

assembly / assemblyMergeStrategy := {
case x if x.endsWith("module-info.class") => MergeStrategy.discard
case x =>
val oldStrategy = (ThisBuild / assemblyMergeStrategy).value
oldStrategy(x)
}

https://github.com/ThijmenL98/DroolsMCVE/pull/1

最新更新