Drools&jBPM Project Model and JAR Based Deployment

Version 5

    Knowledge Project Overview

    Drools&jBPM provides a nice low level api for building executable knowledge engines, in a programmatic way.

    KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
    kbuilder.add( newClasspathResource( "myrulefile.drl" );
    kbuilder.add( newClasspathResource( "myprocessfile.bpmn2" );
    if ( kbuilder.hasErrors() ) {
        fail( kbuilder.getErrors().toString() );
    }
    KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
    kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
    

     

    Those level level apis will stay and still provide an valuable  separation for level interaction with the builder and engine creation. However to improve usability a high level layer approach, using convention and configuration, and thus itself also declarative. This layer sits ontop of the low level programmatic layers.

     

    The Knowledge Project is a maven module that compiles to a jar and is deployment to a maven repository, and cacheable in the local machine m2_repo. The maven module is referred to as Knowledge Module.

     

    The Project Model and deployment must support both static non-hot-incremental deployments and dynamic hot-incremental deployments. non-hot-incremental deployments have all jars on the classapth and nothing changes in the environment after deployment.Hot-incremental deployment has no jars on the classpath and the context is created dynamically at runtime, this environment includes any dependant modules, including class models. Any part of the hot-incremtal deployment context can be updated at runtime; requiring  classloader hackery.

     

    A single knowledge module deployed to a maven repo should be useable in both hot and non-hot incremental situations.

    Knowledge Project (Module) Declaration

    typical eclipse project:

     

    /proj/src/main/java (classpath entry)
           /src/main/resources (classpath entry)
                                           /META-INF/org.test1.kb1-1.0-1.1.xml (changeset)
                                           /META-INF/org.test2.kb2-1.0-1.1.xml
                                           /META-INF/org.test3.kb3-1.0-1.1.xml
                                           /META-INF/kproject.xml
           /src/kbases/org.test1.kb1 (classpath entry)
                                                    /org.test1.kb1-files.dat
                                                    /org/test1/kb1/test1.drl
                                                                            /test2.drl
           /src/kbases/org.test2.kb2 (classpath entry)
                                                    /org.test2.kb2-files.dat
                                                    /org/test2/kb2/test1.drl
                                                                              /test2.drl
    
           /src/kbases/org.test3.kb3 (classpath entry)
                                                   /org.test3.kb3-files.dat
                                                   /org/test3/kb3/test1.drl
                                                                            /test2.drl
    
    

    Each KnowledgeBase has it's own folder under kbases.  Each KBase folder is a classpath entry, this is mostly for a improved visualization within IDE workspaces. The globally unique qualfier for the KBase is used as the root folder name, and typically (but not enforced) matches the namespace used for the files.

     

    When the module is built into a jar all classpath entries are merged, to keep track of which files belong in which KBase, a qualifier-files.dat file is needed, which contains the list of iles. This file is automatically updated as part of the tooling, or the maven build plugin.

    *mdp we could potentially keep the kbase qualifier path in the resulting jar, but that might not work well with tooling, and will need further investigation. If we can do this, and make it work well in tooling, we can drop the qualifier-files.dat

     

    The resulting jar is a maven artifact, that declares maven group and artifact id's. It can be published to a standard m2_repo, and for non-hot-incremental deployment, be part of the classpath and support classpath discovery.

     

    The module must contain a META-INF/kproject.xml that contains the model descriptors for the available KBases and KSessions, including all the relevant configurations to instantiate them. This file is important to support discovery of available KBase and KSession qualifiers for a module. Discovery of kproject.xml follows the same process of beans.xml, in CDI, as per URLScanner

     

    KProjects are fully declarative in that a given qualifier encapsulates all configuration, such as session clock, event processing mode etc, which can only be declared in the kproject.xml. If programmatic configuration was to be allowed it creates ambiguity in what the qualifier's execution beheaviour is. These are the configurations exposed via KnowledgeBaseConfiguration and KnowledgeSessionConfiguration, and not listeners and handlers, which still have yet to be planned.

     

    The KnowledgeSessions (stateful and stateless) also each have a unique qualifier, that is global - it is not scoped to the KnowledegBase.

     

    The changeset is per KnowledgeBase and contains what has been added/removed/updates since the previous version; this informaiton is used to incrementally change a KnowledgeBase at runtime. Note it actually contains all historical diffs, from which it can sitll be updated from, one per version.

     

    six new methods are added to KnowledgeBaseFactoryService. The first three do not specify version. For non-hot-incremental deployments, where jars are on the classpath, it will use the jar with the highest version number.

    *mdp we will have to consider how SNAPSHOTS usage and configuration fits into this.

    boolean hasErrors( String qualifier )
    Collection<Error> getErrors( String qualifier )
    KnowledgeBase getKnowledgeBase( String qualifier )
    

     

    It should also be possible to specify version, if multiple versions of a jar, are on the classpath. Note that if the Jar contains any model information, such as Person, Shop, Book, then normal classloader shadowing issues apply. It is not recommended that models be included within the same jar,if you plan to have multiple versions on the classpath for non-hot-incremental setups.

     boolean hasErrors( String qualifier, String version )
    Colllection<Error> getErrors( String qualifier, String version )
    KnowledgeBase getKnowledgeBase( String qualifier, String version )
    

     

    Knowlodge modules can depend on other modules, allowing one KnowledgeBase to "include" other KnowledgeBases. The inclusion is equivalent to copying all of the knowledge definitions from the source "included" KnowledegBases into the target one  - at runtime. Note only knowledge definitions are included, not configurations.

     

    We need to make sure that  knowledge module can declare a KnowledgeSession utilising a KnowledgeBase from a different module. This is because someone might want to use an available knowledge module, but prefer a different configuration of the KnowledgeSession, that those provided by available qualifiers. If the user wishes to have a different configuration of an available KnowledgeBase, they should "include" the original, so it's effectively a clone, but with a different configuration and also qualifier.

    CDI Portable Extesions

    CDI extensions exist to allow injection of KBases and KSessions, which avoids programmatic lookup via the KnowledgeBaseFactoryService. The portable extension will intercept any KBase or KSession annotation and resolve the instance from the member qualifier, Underneath it's calling KnowledgeBaseFactoryService.getKnowledgeBase( "org.test1.KBase1" ):

     

    private @Inject @KBase("org.test1.KBase1") KnowledgeBase kBase2;
    
    
    private @Inject @KSession("org.test1.KSession1") StatefulKnowledgeSession kSession1;
    
    

     

     

    The portable extension scans all injection points, where it finds @Inject, and for each KBase and KSession it creates a synthetic Bean. This CDI synthetic bean allows the correct engine and session instance to be wired to the variable, for the given qualifier.

     

    Hot-Incremental Deployments