Goals
- Easily reproducebale builds
- a build a a module + dependnencies, all are versioned, to be reprodable.
GAV
Description
Provides group, artifact and version information. This creates a unique key for KieModules.
Programmatic Usage
GAV gav = KieServices.Factory.get().newGAV("mygroup", "myartifact", "1.0-alpha")
KieModule
KieModule represents a deployable unit, physically it's a JAR or a folder. The KieModule contains all java .class files, as well as drl and bpmn2 files. It's content requires a pom.properties and kmodule.xml. The KieModule is uniquely identified by a GAV. There are currently three implementations:
FileKieModule
points to a folder, typically an IDE project folder.
ZipKieModule
points to a zip file
MemoryKeyModule
in memory "folder", used for runtime generated KieModule's.
A KieModule can have dependencies, which are defined in the pom.xml. When programmatically registering a KieModule, in the KieRepository, you should pass the other KieModule's as vararg. If kie-ci is to retreive a KieModule it will determine the missing (non classpath) dependencies and add them to the vararg.
Methods
Have kept purposefully minimumal for now.
- GAV getGAV()
- Collection<KieModule> getDependencies
- @TODO (mdp)
- @TODO (mdp)
KieProject
Maven has the concepts of projects and modules. A project can consist 1 or 1...n modules, referred to as single-module and multi-module projects. as you can guess a single module project is just a module, there is no additioal project informaiton. A multi-module project requires a root parent. The root parent is itself a module, but typically just lists the dependant modules.
In Kie there is no actual public KieProject class. Only a root KieModule and it's dependencies. I only add this section so people can understand the relationship between single and multimodule projects, and pom vs jar packaging. As per maven that root KieModule may be empty and simply exist to list it dependencies, or it may contain assets and also a list of dependencies.
kie-ci can take care of loading in pom packaged jars and the dependencies it provides. If kie-ci is not used, it is necessary to manually add the root "parent" KieModule and it's dependencies as vararg list. The root KieModule provides the unique GAV.
kmodule.xml
The kmodule provides a list of named and configured KieBases and KieSessions for a KieModule.
Schema
Kitchen sink example:
The kmodule.xml facilitates module classpath discovey. Java can provide all kmodule.xml on the claspath, via getResources("META-INF/kmodule.xml"), from there we can get the root of the jar or folder.
@TODO (mdp): Further a kmodule may declare one default KieBase, one default stateless KieSession and one default stateful KieSession. This is done by the default="true/false" attribute.
If a KieModule has dependencies we can have the following situations,
- Classpath
- multiple modules on the classpath declare defaults
- Do we fail fast (runtimexception) and insist only one default (we don't know what the root KieModule is)
- multiple modules on the classpath declare defaults
- Dynamic module, root module plus dependencies. All three should be detectable at compile time.
- 1) Ignore defaults in dependencies, only allow the root to declare them
- 2) Allow root to override any dependency, so we allow shadowing
- 3) if root does not declare and multiple entires for dependencies, fail fast
pom.properties pom.xml
Each KieModule jar/folder also requires a pom.properties. From this the GAV can be discovered. This file is produced by maven when building a jar, however when working in an IDE the pom.properties is not yet produced in the project folder. In this case we attempt to recurse up to find the pom.xml and get the GAV from there, and then generate the pom.properties.
KieRepository
KieRepository provides an api to store and retreive KieModules. Further if kie-ci is on the classpath it can use embedded maven to retreive KieModules from the local and remote m2 repos.
Methods
- void addKieModule(KieModule kModule)
- Adds a KieModule to the repo
- KieModule addKieModule(Resource resource, Resource... dependencies)
- Adds a KieModule, with it's dependencies to the repo.
- KieModule getKieModule(GAV gav)
- Gets a KieModule, if it was not manually added and kie-ci is on the classpath it'll fall back to embedded maven to retrieve it.
manually deploy and use a dynamic KieModule:
KieModule kModule = kr.addKieModule( ks.getResources().newFileSystemResource( getFile("example1") ) ); KieContainer kContainer = ks.getKieContainer( kModule.getGAV() );
manually deploy and use a dynamic KieModule with dependencies:
Resource ex1Res = ks.getResources().newFileSystemResource( getFile("example1") ) ; Resource ex2Res = ks.getResources().newFileSystemResource( getFile("example2") ) ; KieModule kModule = kr.addKieModule(ex1Res, ex2Res); KieContainer kContainer = ks.getKieContainer( kModule.getGAV() );
Use a KieModule alreadyy deployed to a local or remote m2_repo, requires ki-ci on the classpath.
KieContainer kContainer = ks.getKieContainer( ks.newGAV("org.domain", "artifactId", "1.0) );
KieContainer
A KieModule and it's dependency is deployed into a KieContainer which makes it's contents available for use at runtime. The KieContainer allows the lookup of named KieBases and KieSessions
- Result verify()
- getKieBase()
- Returns a default KieBase, configured as per the kmodule xml.
- a kmodule.xml may have a single KieBase with the default="true" attribute.
- Returns a default KieBase, configured as per the kmodule xml.
- newKieSession()
- Returns a default KieSession, configured as per the kmodule xml.
- a kmodule.xml may have a single stateful KieSession with the default="true" attribute.
- Returns a default KieSession, configured as per the kmodule xml.
- newStatelessKieSession()
- Returns a default StatelessKieSession, configured as per the kmodule xml.
- a kmodule.xml may have a single stateless KieSession with the default="true" attribute.
- Returns a default StatelessKieSession, configured as per the kmodule xml.
- getKieBase(String name)
- Returns a named KieBase, configured as per the kmodule xml.
- newKieSession(String name)
- Returns a new named KieSession, configured as per the kmodule xml.
- newStatelessKieSession(String name)
- Returns a new named KieStatelessSession, configured as per the kmodule xml.
- There is a special default classpath KieContainer which is made up of all the KieModules on the classpath, it has no root/parent GAV as it's not possible to determien this.
KieServices ks = KieServices.Factory.get(); KieContainer kContainer = ks.getKieClasspathContainer(); KieSession kSession = kContainer.newKieSession( "ksession1" );
A dynamic module KieContainer, you don't need to define dependencies when getting, as that was defined when adding.
KieContainer kContainer = ks.getKieContainer( kModule.getGAV() ); KieSession kSession = kContainer.newKieSession( "ksession1" );
KieBuilder
The KieBuilder provides a standard way to do runtime code generation and for dynamic KieModule.
methods
- setDependencies(Resource... resources)
- May be called just once
- setDependencies(KieModule... dependencies)
- May be called just once
- Results build()
- hasResults(Level... levels):
- getResults(Level... levels):
A KieModule with no dependencies, and default generated pom.properties and kmodule.xml:
KieFactory kf = KieFactory.Factory.get(); KieFileSystem kfs = kf.newKieFileSystem(); kfs.write( "src/main/resources/org/kie/example5/HAL5.drl", getRule() ); KieBuilder kb = ks.newKieBuilder( kfs ); kb.build(); // kieModule is automatically deployed to KieRepository if successfully built. if ( kb.hasResults( Level.ERROR ) ) { throw new RuntimeException( "Build Errors:\n" + kb.getResults().toString() ); } KieContainer kContainer = ks.getKieContainer( kr.getDefaultGAV() );
The KieFileSystem has some helper methods, if people wish to generate pom.properties and kmodule.xml:
- KieFileSystem generateAndWritePomXML(GAV gav);
- KieFileSystem writePomXML(byte[] content);
- KieFileSystem writePomXML(String content);
- KieFileSystem writeKModuleXML(byte[] content);
- KieFileSystem writeKModuleXML(String content);
** UPDATE: The Resource API should discover resource names when possible and allow resources to be named when not discoverable, like for byte array resources:
Resource ruleResource = ResourceFactory.newByteArrayResource( getRule(), ResourceType.DRL ).setName( "somepackage/rule.drl" );
This allows the resource to be written to the KieFileSystem without requiring respecifying names and paths:
kfs.writeResource( ruleResource );
** UPDATE 2: The resource API should keep resource configuration and allow it to be retrieved:
Resource dt = ResourceFactory.newClassPathResource( "/data/IntegrationExampleTest.xls", getClass()).setType(ResourceType.DTABLE).setConf(conf);
This allows the KieFileSystem to automatically retrieve and write the configuration down to a conf file in the filesystem.
Default GAV, pom.properties and kmodule.xml
The KieBuilder will generate a default pom.properties and a default kmodule.xml. The pom.properties will be taken from the default GAV, see KieRepository.getDefaultGAV() - so it is not suitable for deployment in a maven repository.
The kmodule.xml will be generated with a single kbase and two ksession entries - one session for stateful and one session for stateless. These wll be used by the default methods on the container. Additionally the name of the kbase will be special which the builder detects and thus includes all resources for the jar, not just a single package.
The maven plugin can also generate a kmodule.xml, maven itself will generate a pom.properties, so this is never needed by us.
Static Factories vs Service Interfaces
Drools 5.x used static factories for things, which kept it compact:
- KnowledgeBuilderFactory.newKnowledgebuilder();
- KnowledgeBaseFactory.newKnowledgeBase();
- CommandFactory.newFilreAllRulesCommand();
These factories have no interfaces and thus don't work with OSGi, Spring and CDI. To address this we shadowed all factories with interfaces.
- KnowledegBuilderFactoryService
- KnowledgeBaseFactoryService
These factory services had to be looked up from the ServiceRegistry:
KnowledegBuilderFactoryService kbfs = ServiceRegistrImpl.get( KnowledegBuilderFactoryService.class ) kbfs.newKnowledegBuilder();
The additional lines mean that outside of a container people still preferred the static factories. However maintianing a duel set of static factories and interface services is cumbersome, and one may lag the other. It also maks for long confusing class names, and avoids the "single way" we are trying to promote with 6.x.
To address this 6.x only uses service interfaces, with a single static method to retrieve the service.
KieService ks = KieServices.Factory.get();
Comments