Embedding and Testing Drools Flow in your Java Project

Posted on Monday, March 21, 2011

0


Drools Flow provides workflow capabilities and can easily integrate rules with processes. You can easily define the series of steps that would be followed in a workflow using the flowchart based approach to get a rule file. All this works like a charm with the drools plugin in eclipse and if you are interested then there is good information here to work with the plugin. This post however talks about a few struggles that I had to face to embed the drools flow in my Java based project.

We use maven for building our projects for a couple of reasons. First, we like it as a build tool and second, a fellow Inphiner is authoring a book on Maven. So we are bound to be biased.

Anyway, one of the problems that I see with the maven way of doing things is that many big projects would host a maven repository on their own rather that put it on maven central. Though, I am not a proponent of this approach as it makes findings libraries difficult for me as a developer, however, as per Spring, there are reasons why they do it that way. JBoss also does it this way.

The repository for Jboss through which you would get the drools file is

 <repository>
	<id>jboss-public-repository-group</id>
	<name>JBoss Public Repository Group</name>
	<url>http://repository.jboss.org/nexus/content/groups/public-jboss/</url>
   </repository>

Then you would need a few dependencies to make Drools work within your project, these are

<properties>
    <drools.process.version>5.1.1</drools.process.version>
    <xstream.version>1.2.2</xstream.version>
  </properties>

<dependency>
	<groupId>org.drools</groupId>
	<artifactId>drools-process-task</artifactId>
	<version>${drools.process.version}</version>
      </dependency>
      <dependency>
	<groupId>org.drools</groupId>
	<artifactId>drools-core</artifactId>
	<version>${drools.process.version}</version>
      </dependency>
      <dependency>
	<groupId>org.drools</groupId>
	<artifactId>drools-compiler</artifactId>
	<version>${drools.process.version}</version>
      </dependency>
      <dependency>
	<groupId>xstream</groupId>
	<artifactId>xstream</artifactId>
	<version>${xstream.version}</version>
      </dependency>

notice that I used, 5.1.1, there is 5.2.0.Snapshot as well but when I checked, that does not exist for drools-process-task. The main libraries required are drools-compiler, drools-core and drools-process-task. There is also an xstream requirement.

Once this was done, as a sample, I was able to execute the following code in my project

public static final void main(String[] args) {
		try {
			// load up the knowledge base
			KnowledgeBase kbase = readKnowledgeBase();
			StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
			KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");


			SampleEntity entity = new SampleEntity();
			entity.setEntityName("Cars");

			Set<SampleAttribute> attributes = new HashSet<SampleAttribute>();
			SampleAttribute attribute1 = new SampleAttribute();
			attribute1.setAttributeName("color");
			attribute1.setAttributeType("red");
			SampleAttribute attribute2 = new SampleAttribute();
			attribute2.setAttributeName("shape");

			entity.setAttributes(attributes );

			ksession.insert(entity);
			ksession.insert(attribute1);


			// start a new process instance
			ksession.startProcess("com.sample.ruleflow");
			logger.close();
		} catch (Throwable t) {
			t.printStackTrace();
		}
	}

	private static KnowledgeBase readKnowledgeBase() throws Exception {
		KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
		kbuilder.add(ResourceFactory.newClassPathResource("ruleflow.rf"), ResourceType.DRF);
		KnowledgeBuilderErrors errors = kbuilder.getErrors();
		if (errors.size() > 0) {
			for (KnowledgeBuilderError error: errors) {
				System.err.println(error);
			}
			throw new IllegalArgumentException("Could not parse knowledge.");
		}
		KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
		kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
		return kbase;
	}

For acceptance testing, we use fitnesse. I included all the drools jars in my fitnesse library path as

classpath: /home/vikas/.m2/repository/org/drools/drools-api/5.1.1/drools-api-5.1.1.jar
classpath: /home/vikas/.m2/repository/org/drools/drools-compiler/5.1.1/drools-compiler-5.1.1.jar
classpath: /home/vikas/.m2/repository/org/drools/drools-core/5.1.1/drools-core-5.1.1.jar
classpath: /home/vikas/.m2/repository/org/drools/drools-process-task/5.1.1/drools-process-task-5.1.1.jar
classpath: /home/vikas/.m2/repository/org/drools/drools-workitems/5.1.1/drools-workitems-5.1.1.jar

However, the test would not run for the want to eclipse jdt. Hence I included the following

classpath: /home/vikas/.m2/repository/org/eclipse/jdt/core/compiler/ecj/3.5.1/ecj-3.5.1.jar
classpath: /home/vikas/.m2/repository/org/antlr/antlr-runtime/3.1.3/antlr-runtime-3.1.3.jar

Now, the functionality of drools flow that I am using right now works like a charm both inside my Java project as well as Fitnesse.

Advertisements
Posted in: Java