Pages

Showing posts with label jboss drools. Show all posts
Showing posts with label jboss drools. Show all posts

Saturday, September 26, 2009

JBoss Drools Content Repository

JBoss Drools project features a BRMS called Guvnor. Drools Guvnor features a rich web based GUI, including editors and other stuff. Sometimes you cannot really use Guvnor in your deployment due to some bureaucratic issues: for instance, all the web UIs in our organization are Flex-based and Guvnor's UI is GWT-based (there might be other reasons for sure). So you want to use Drools but your obliged to use the tools/frameworks that are approved in your organization.

There are some issues that you have to pay attention to when starting to use Drools:
  • How to store the rules?
  • How to version the rules?
  • What will be your deployment scheme?
  • Who will manage the rules?
  • Can the domain experts understand how the rule editors work?
  • etc

In this post I'd like to cover how the rules are stored with drools-repository module of JBoss Drools.

Friday, January 16, 2009

JBoss Drools: Reasoning on QuickFIX-J data model

I just tried to make a simple JBoss Drools example which could probably handle QuickFIX-J messages. So I created the simplest rule flow, including one RuleSet node, mapped onto a ruleflow-group in a DRL file.

Simple Drools Flow Example
same in textual form:

<?xml version="1.0" encoding="UTF-8"?>
<process xmlns="http://drools.org/drools-5.0/process"
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation="http://drools.org/drools-5.0/process drools-processes-5.0.xsd"
type="RuleFlow" name="oms" id="my.oms" package-name="my.oms" >

<header>
</header>

<nodes>
<start id="1" name="Start" x="16" y="16" width="80" height="40" />
<actionNode id="2" name="Action" x="128" y="16" width="80" height="40" >
<action type="expression" dialect="java" >System.out.println("Action Start");</action>
</actionNode>
<ruleSet id="3" name="RuleSet" x="240" y="16" width="80" height="40" ruleFlowGroup="my-oms" />
<actionNode id="4" name="Action" x="352" y="16" width="80" height="40" >
<action type="expression" dialect="java" >System.out.println("Action End");</action>
</actionNode>
<end id="5" name="End" x="464" y="16" width="80" height="40" />
</nodes>

<connections>
<connection from="1" to="2" />
<connection from="2" to="3" />
<connection from="3" to="4" />
<connection from="4" to="5" />
</connections>

</process>


Next describe to rule in a DRL file:


package my.oms

import quickfix.fix44.NewOrderSingle
import quickfix.field.MinQty

rule "reset minqty"
dialect "mvel"
ruleflow-group "my-oms"
when
$order : NewOrderSingle($qty : minQty)
MinQty(value == 1.0 || value > 100.0) from $qty
then
System.out.println("reset order: " + $order);
modify($order){
$order.set(new MinQty(20));
}
end

What looks a little strange to me is the when part:

$order : NewOrderSingle($qty : minQty)
MinQty(value == 1.0 || value > 100.0) from $qty

I spent just quite a few minutes to figure out why my first version of the rule didn't work as I expected. It seemed to me that it would be more natural to make it just in one line, something like this:

NewOrderSingle(MinQty(value == 1.0 || value > 100.0))


With a Java code from the Drools examples (which may also are generated when you create a Drools Project with the Drools eclipse plug-in), I run the example and it works fine.

package my.oms;

import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.*;
import org.drools.io.ResourceFactory;
import org.drools.logger.KnowledgeRuntimeLogger;
import org.drools.logger.KnowledgeRuntimeLoggerFactory;
import org.drools.runtime.StatefulKnowledgeSession;

import quickfix.field.MinQty;
import quickfix.fix44.NewOrderSingle;


public class MyOms {

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");
// go !

NewOrderSingle order = new NewOrderSingle();
order.set(new MinQty(1.0));

NewOrderSingle order1 = new NewOrderSingle();
order1.set(new MinQty(111.0));

NewOrderSingle order2 = new NewOrderSingle();
order2.set(new MinQty(222.0));

ksession.insert(order);
ksession.insert(order1);
ksession.insert(order2);
ksession.startProcess("my.oms");
ksession.fireAllRules();

logger.close();
} catch (Throwable t) {
t.printStackTrace();
}
}

private static KnowledgeBase readKnowledgeBase() throws Exception {
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("oms.drl"), ResourceType.DRL);
kbuilder.add(ResourceFactory.newClassPathResource("oms.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;
}

}


This example just shows that with Drools one may handle even quite complex data model, such as QuickFIX-J's one. Next, it would have real value if I'm able to make do the same via Guvnor.

Thursday, November 20, 2008

Code Kata: The Business Rules

I'm thinking of an application for JBoss Drools. We are given a task to design a system for order management (OMS), which will sit behind a FIX gateway and serve several internal and external systems. One thing is for sure - we are to take a challenge to organize and maintain a large set of business rules and this brings up some memories.

In 2004 a colleague told me about code kata. These are the good exercises to do when learning a new language, or just empirically solve some common problems. One of the puzzlers sit in my mind permanently since then - The Business Rules Kata, which is about the hard to maintain complex business rules.
How can you tame these wild business rules? How can you build a system that will be flexible enough to handle both the complexity and the need for change? And how can you do it without condemming yourself to years and years of mindless support?

We face all these problems daily while coding the business logic for our banking system. One of the approaches some developers have taken is that
the if-the statements can be avoided while using appropriate OOP techniques

The problem is that sometimes while avoiding those if-statements the code becomes over-engineered due to a large number of classes. And it is still doesn't solve the problem of quick changes that are very hard to implement in a big organization with the "release process".

Recently I've found a discussion at joelonsoftware.com. It is dated 2005 but I think not much have changed since then. I think that most of the developers are still fighting the complexity of the business rules and in future it will still be a challenge.

My next step is to create a demo using JBoss Drools, QuickFIX/J. Apache Camel can be used to integrate both into one flow.

Also what is really cool about Drools is that it would allow our clients to maintain the order validation rules apart of the overall release process using Guvnor. So the changes in order validation logic could be introduced rapidly.

Saturday, August 9, 2008

More Widgets for Guvnor

For properties and XML editors in Guvnor I'm trying to make use of GWT-Ext components. The widgets from this library look really nice. Also the API looks OK. For the properties widget, theres a PropertiesGridPanel available, which provides some nice features for editing the properties (see the screenshot below).



.. and a piece of code that assembles the panel:

PropertyGridPanel grid = new PropertyGridPanel();
GridView view = new GridView();
grid.setView(view);
Map map = new HashMap();
PropertyHolder[] props = getProps(); //RPC call here
for (PropertyHolder holder : props.list) {
map.put(holder.name,holder.value);
}
grid.setSource(map);

How does it know which editor should be attached to the value column? Simple the type is known at the compile time! One of the benefits of GWT is claimed to be its performance. It is fast, but this power comes at a price - you cannot leave the type undefined, i.e. you cannot use java.lang.Object for the type of your class members.

Consider the following class, which is intended for exchanging the information via RPC calls:

public class PropertyHolder implements IsSerializable {
public String name;
public Object value; // coudn't use Object type here
}


While trying to compile this code down to javaScript, we'll get the following messages from the GWT's compiler:
org.drools.guvnor.client.ruleeditor.PropertyHolder
[java] Analyzing the fields of type 'org.drools.guvnor.client.ruleeditor.PropertyHolder' that qualify for serialization
[java] public java.lang.Object value
[java] java.lang.Object
[java] [ERROR] In order to produce smaller client-side code, 'Object' is not allowed; consider using a more specific type
[java] [ERROR] Type 'org.drools.guvnor.client.ruleeditor.PropertyHolder' was not serializable and has no concrete serializable subtypes

So that's it! I couldn't think of any solution how to cheat the compiler and leave the value's type undefined, so I have to use strings for now.

Friday, July 25, 2008

GSOC2008: The Pluggable Editors for Guvnor

One of the goals in this year's GSoC project for me is to enable plugging of content editors as jars. Today I've completed the automation for this aim.

I've integrated the rolodex widget for using image data in Guvnor. Next, the aim was to isolate the code into a separate place, so that it doesn't affect the base source code, and using some code generation routines integrate the new widget to Guvnor.


Here's the summary:

  • The pluggable code is moved into modules/ directory under drools-guvnor

  • build.xml was extended to generate some code pieces to integrate the pluggable editors. Some classes in Guvnor required a minor refactoring in order to support code generation.


It is not as smooth as it could be in GuvnorNG, but the goal is achieved to some extent, I think :)

Friday, July 18, 2008

GSOC2008: Rolodex Panel Assembly for Guvnor

In my previous post about integrating rolodex into Guvnor I tried to create the example just with a set of pre-compiled images which are then assembled into drools-guvnor.war. But the real goal is actually to display the pictures stored in Jackrabbit repository for Guvnor.
Now, after some experiments with rolodex and Guvnor, I have a widget where one may upload a picture and display it.


Currently it can accept only one picture per RuleAsset class instance. Therefore the content handler for this asset should be extended to support multiple images per RuleAsset.

RolodexCardBundle images = getImagesFromAsset();
RolodexCard[] rolodexCards = images.getRolodexCards();
if (rolodexCards.length > 0) {
final RolodexPanel rolodex =
new RolodexPanel(images, 3, rolodexCards[0], true);
layout.addRow(rolodex);
}

I have set the hight of the panel manually as the picture was cropped otherwise in the widget. (Don't know the reason yet). getImagesFromAsset() is used for converting the asset's content to the RolodexCard:

public RolodexCardBundle getImagesFromAsset() {
return new RolodexCardBundle() {
public int getMaxHeight() {
return 200;
}

ClippedImagePrototype clip = new ClippedImagePrototype(
GWT.getModuleBaseURL() +
"asset?" + HTMLFileManagerFields.FORM_FIELD_UUID +
"=" + asset.uuid
,
0, 0, 300, 200 );

RolodexCard card =
new RolodexCard(clip, clip, clip, 300, 100, 10);

public RolodexCard[] getRolodexCards() {
return new RolodexCard[]{card};
}
};
}

I've cheated with the code that composes the RolodexCard, as ClippedImagePrototype's javadoc says:
This class is used internally by the image bundle generator and is not intended for general use. It is subject to change without warning.
But the implementation of ClippedImagePrototype is actually what I need. Probably, if it is really the subject to change at any time, I would rather cope'n'paste this class into Guvnor code base.

TODO:
A heavy part of the work will have to be carried out by the content handler. The content handler will have to support the multiple images per asset and also perform some graphics routines in order to replace the pre-compilation phase implemented in rolodex to adjust images.

Tuesday, July 15, 2008

GSOC2008: Integrating Rolodex to Guvnor

In Guvnor, there are many different widgets that are used to display or edit different assets. One interesting widget is about to be added - a widget that could accept images and display them. For this purpose, rolodex, a widget that can display a stack of images, can be used. Rolodex uses deferred binding for the image generation and animation. Let's see how can we quickly add a new widget displaying some predefined images.

First, create a class, implementing RolodexCardBundle interface (from the rolodex library) and declare a few methods that will return the images (just like ImageBundle described in the book):


public abstract class Images implements RolodexCardBundle {

/**
* @gwt.resource img_3861.jpg
*/
public abstract RolodexCard imgA();

/**
* @gwt.resource img_3863.jpg
*/
public abstract RolodexCard imgB();

/**
* @gwt.resource img_3865.jpg
*/
public abstract RolodexCard imgC();

...

private final RolodexCard[] cards = new RolodexCard[]{
imgA(), imgB(), imgC()
};

public RolodexCard[] getRolodexCards() {
return cards;
}


Next, to display those images, create ImageSetWidget (or you-name-it) class extending DirtyableComposite:

public class ImageSetEditor extends DirtyableComposite {
// asset and viewer are not used now...
public ImageSetEditor(RuleAsset asset, RuleViewer viewer) {
final Images images = (Images) GWT.create(Images.class);
final RolodexPanel rolodex
= new RolodexPanel(images, 3, images.imgA(), true);
initWidget(rolodex);
}
}


For Guvnor to be able to launch the editor, we have to modify EditorLauncher class:

...
else if (asset.metaData.format.equals(AssetFormats.IMAGE_SET)) {
return new ImageSetEditor(asset, viewer);
...

AssetFormats should be supplied with the new constant for this new type, of course.

To allow user to create such widgets in UI, a new menu item needs to be added.


This means, ExplorerLayoutManger#rulesNewMenu() should be modified:

m.addItem(new Item("New ImageSet",
new BaseItemListenerAdapter() {
public void onClick(BaseItem item, EventObject e) {
launchWizard(AssetFormats.IMAGE_SET, "New ImageSet", true);
}
}, "images/rule_asset.gif"));

And last, but not least we need to include the following line in Guvnor.gwt.xml:
<inherits name='com.yesmail.gwt.rolodex.Rolodex'/>


Now, after the project has been rebuilt and redeployed we get the following widget on the screen:


Currenly, the widget is displaying a predefined set of images and animates them as we roll the mouse over. So we have now a rolodex-powered widget inside Guvnor. Sounds cool! :)

Now, there are a lot of TODOs to make use of this new cool widget.

  • Menus should be pluggable. So far I knew that the only class that we should generate in order to support adding new rule editor widgets. Without doubt, a user needs a button to create the widget in his workspace, and therefor we should inject the new menu item. I suppose we can generate this part also. Therefore we need to extract the ExplorerLayoutManger#rulesNewMenu() method into a separate class.
    Currently I have an ant task ready to generate a new EditorLauncher class source to plug a new asset type editor. But perhaps, if we have more of these classes to be generated, I'd better add a new ruby script to do this job.

  • Upload of new images. There's no use of this widget if it can redisplay only the predefined set of images.



  • RuleAsset support for images.The images should be supplied via the RuleAsset, i.e. the content should be a class that could represent a set of images.


  • A content handler is required as well.

Wednesday, June 11, 2008

GSOC2008: GWT magic - Deferred Binding and Generators

While reading the book further, I realized that I do not need any special library for plugging new content editors to Guvnor.

Currently, the editors are instantiated via EditorLauncher class, which provides several static methods for working with the editors. Now, we could actually remove the static property, change EditorLauncher to be interface and instantiate EditorLauncher like this:
EditorLauncher launcher = (EditorLauncher) GWT.create(EditorLauncher.class)

This will actually force the EditorLauncher implementation to be generated at the compile time using our generator (which would be subclassed from com.google.gwt.core.ext.Generator). This cool feature of GWT is called deferred binding ...
... which works by resolving and inserting the required class during compile time instead of runtime, as is the case in the Java language.

Basically, the need for any external library is diminishing in this case.

Tuesday, June 10, 2008

GSOC2008: Reflection Libraries for GWT

GWT Reflection appeared to have GPL licence and thus cannot be incorporated into Drools code base :(
I've found another library which has the support for introspection/reflection of Java beans - Gwittir, which comes with LGPL, and thus can only be included as a jar, but actually it doesn't provide the functionality that could provide us the features for plugging the content editors via Java Reflection API. So anyway we need to extend it.
I think I better go my own path and re-implement the code generation myself. There are 2 reasons for that: I will have the better understanding of the mechanisms behind GWT, and also improve my commit rate for the project :)

Sunday, June 8, 2008

GSOC2008: GWT Reflection for Pluggable Content Editors in Guvnor

GWT Reflection is a cool project which inspired Mike for the idea of pluggable content editors for Guvnor (aka JBoss Drools BRMS). The challenge is that the content editors are selected on the client side and therefore we couldn't use Java's reflection API in order to enable the plug-in functionality. But with the GWT Reflection we can probably get as close as possible. GWT Reflection does a lot of what we need but most probably we'll need some more features and therefore I'm integrating it into Guvnor's codebase at the moment. I hope I will have some basic workflow ready next week. Stay tuned! :)

Tuesday, May 27, 2008

GSOC2008: My First Contribution

On the first coding day (or I'd better say *night*) I was surfing Guvnor (former Drools BRMS) codebase. I've noticed some flaws in the code so I did some refactoring to achieve my first commit :) A cyclic dependency between org.drools.brms.server.contenthandler.ContentHandler and org.drools.brms.server.contenthandler.ContentManager was removed.

Tuesday, April 22, 2008

Google Summer of Code 2008: Application Accepted!

I've got my GSoC application accepted again! This time I've applied to JBoss.org project Drools for extending Guvnor framework. Red Hat got 12 slots in total for Fedora and JBoss.org projects (10 for Fedora and only 2(!) for JBoss.org), Here's the project list. And here's some more stats.

So, happy summer coding to me! :)

Disqus for Code Impossible