DroolsProject

 

We need to defacto ways to build projects by convention and configuration, as an alternative to the current knowledge builder api.

 

We'll borrow the OSGI idea of a "bundle" for now to indicate a zipped project.

 

Layout

  • 0..1 bundle
    • 1..n resource paths (like eclipse classpath entries)
      • 1..n packages
        • 1..n ProcessModule
          • 1..n bpmn2
        • 1..n RuleModules (collection of rules, like agenda groups, see RuleModule )
          • 1..n Rules

 

Layout Example

  • bundle (eclipse project)
    • main/java
      • org/domain/xxx
        • file1.java
        • file2.java
        • file3.drl // drl files in the java space provide type declarations and functions
        • file4.drl // drl files in the java space provide type declarations and functions
    • main/kbase1 (kbase1 is the id name for the kbase)
      • org/domain/xxx
        • ProcessModule pm1
          • bpmfile1.bpmn2
          • bpmfile2.bpmn2
        • RuleModule rm1
          • rulefile1.drl
          • rulefile2.drl
    • main/kbase2 (kbase2 is the id name for the kbase)
        • org/domain/yyy
        • ProcessModule pm1
          • bpmfile1.bpmn2
          • bpmfile2.bpmn2
          • RuleModule rm1
            • rulefile1.drl
            • rulefile2.drl
    • main/kbase3 extenda kbase2 // we allow for "parent" kbases
        • org/domain/yyy
        • ProcessModule pm1
          • ....
        • RuleModule rm1
          • ....

Conventions and Behaviours

  • Each KBase will map to resource path (classpath entry) folder.
    • There can only be one KBase per resource path. All sub folders for that path make up that KBase.
    • There is a meta file with an entry per resource path that tracks all folders and files in that path, similar to the spring xml we have now already. This is maintained by the tooling and ensures when the paths are merged into a single bundle zip we can track which rules go in which kbase. It also provides a name for the kbase, which will allow for annotation injection.
  • Meta file that defines named knowledge bases, also does the same for sessions
    • A Bundle provides export information, that works with annotation driven wiring
      • list of named kbases
      • list of named ksessions, if the bundle defines any
      • list of named channels
  • File entries must follow java like conventions such that the package maps to a folder structure and rule modules and rules for that package are in that folder.
  • Single classloader at the bundle level, all KBases for that bundle use the same classloader. Thus a type declaration's definition is visible to all java classes and kbase's in that bundle.
    • We might possible add "scoped" type declarations, via a keyword. Which would only be visible to that KBase path, however this makes tooling a lot more complicated, so needs to be though through carefully.
      • For instance if they really need isolation, why not just do it in another project bundle?
  • Type Declarations are also global for the bundle and must be declared in their correct package namespace
    • I'm tempted to say that type declarations should be a different resource path, same for functions. As it doesn't make sense to declare them inside of a kbase path, yet have them global to all kbases.
  • A Kbase can declare that it extends another.
    • This effectively merges the parent into the child for a single child kbase.
  • Maven pom should be able to build a knowledge bundle
    • essential for the project to fit in with existing architecture approaches
  • Any file, or the entire bundle, may be synced with an external source, like guvnor, that information should be recorded and tracked as part of the bundle information. It should record the version and the url fo the external resource.

 

Annotations

The Bundle itself will build kbses and ksessions and allow those to be injected where needed:

@KnowledgeBase

  • Will inject the kbase instance

@StatefulKnowledgeSession

  • Create and return new StatefulKnowledgeSession from a known kbase
  • Return a registered existnig StatefulKnowledgeSession

@StatelessKnowlegeSession

  • Always creates and returns a new StatelessKnowlegeSession

@Query

  • Injects a query from a registered ksession

 

We can also use annotations that will wire themselves into known ksessions, such as listeners or query handles:

@ReactiveQuery

  • Must specify a registered StatefulKnowledgeSession and query within that session
  • Will also automatically wire the listener to that ksession to receive live updates

@WorkingMemoryEventListner,AgendaEventListner,ProcessEventListener

  • Must specify a registered StatefulKnowledgeSession and query within that session
  • Will also automatically wire the listener to that ksession to receive live updates

 

Version Management and Incremental Updates

Each bundle specifies it's current version but aso provides provide change information. This information lists all added, removed and changed files from  the previous version. However the bundle contains all changes sets for each version diff. This information makes it possible to statefully upgrade any existing bundle to the new one, by merging the change sets from the current deployed version to the target version.

 

Any updates will need to be validated first, to ensure they will succeed and retain integrity.

  • Cannot remove Classes or fields used by existing rules or processes.
  • Cannot change Class if instances exist for that class
    • At some point we might allow for mini auto-migration scripts which can handle conversion.

 

JIT and CodeGeneration

It should noe be possible and optional to pre-generate all bytecode ahead of time and store it in the zip, so that it's accessible when the system needs it. This needs to be optional as those both building and running on the same machine at the same time may wish to delay JIT to spread out the cpu hit.

 

Version Compatability

For performance reasons we need to store the serialised package's in the Bundle, similar to how we pass around packages now. However we still do not have binary compatability across rule versions. The compiled with version should be stored, if the client does not match that, the sysem can fall back to the drl (also stored in the bundle) and compile on demand.

 

Over time we hope to develop an intermediary langauge that is a compromise between binary compatability across versions and performance.

 

Project Scoped WorkingMemory

Typically each KnowledgeBase has it's own working memory that objects must be inserted into. We can probalby have an additional project scoped  working memory, any instances inserted/retracted/modified in here are available to all created kbase's ksessions. i.e. you isnert into this project working memory and that fact is inserted into all the ksession's for all the kbases, and vice versa if you do a remove. So it's more like a shared object store.

 

RuleModule and ProcessModule

RuleModule and ProcessModule are java classes that expose an auto wired listener model and provide some pluggable services.

In the layout the drl and bpmn2 files are shown as nested folders ot the module. It is open an open question as to whether they are physically nested in a folder or instead in the same folder with header information that specifies their parent module.

 

RuleModule is still being specced and very early stages, but in essence it would look something like below: please take as illustrative only, as we will determine this more thoroughly later in the RuleModuleand ProcessModule spec documents.

We'll initially provide pure pojo ones and allow for compact drl definition ones too at a later date.

It is likely we'll have definitions by both interfaces and annotations. Annotations can be ideal as they do not require dummy methods, where as interfaces need all methods ot be declared, even if not used.

@RuleModule(name == "my rule module 1") // default is the class name
public class MyRuleModule1 {
    public void onBeforeEnter();
    public void onEnter();

    public void onBeforeExit();
    public void onExit();

    public void onMatch(Match match) {}

    public void onUnMatch(Match match) {}

    public void onCancelFire(Match match) {}

    public void onBeforeFired(Match match) {}

    public void onAfterFired(Match match) {}
}

 

The RuleModule is assocated with the kbase and all rule matching and execution would trigger the relevant callback. Note there is no wiring for the end user, simply delcare it it works - you do not manually add this to the kbase, as you do with listeners currently. As shown in RuleModule spec, these implementations can provide extensible behavioural change to rules. Will do a similar thing for ProcessModule.