Tuesday, May 05, 2009
In order to use the (amazingly cool) Drools rules engine in a .NET world, you've got to figure out how to pass your .NET business object over there to the land of Java. There are a couple of ways to do this. I wanted a straightforward way that didn't rely on any 3rd party tools. Here's the gist of what we're trying to accomplish:
- Instantiate a .NET object; populate with values.
- Serialize the object and send it to a queue.
- Java application monitors the queue; picks up the message text.
- Java app unmarshals (i.e. deserializes) the text into a Java object.
- Java app fires the rules, previously loaded, which may or may not modify the Java object's properties.
- Java app marshals (i.e. serializes) the resulting object, and sends it to a queue.
- .NET queue monitor picks up the message, deserializes it into a .NET object.
- Excellent!
To achieve this type of scenario just takes a bit of setup with the objects you intend to pass back and forth. Here's one way how to do that setup.
A. Create your .NET object.
Create a class library in .NET. Here's an example of something we can tinker with for the duration of this blog series. Compile it into a dll.
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Xml.Serialization;
6:
7: namespace ZenDoodle.Common.Messaging.Models
8: {
9: [XmlRoot(Namespace = "http://zendoodle.com/messaging/XML-Schema/2009",
10: ElementName = "Customer")]
11: public class Customer
12: {
13: public string Name { get; set; }
14: public string Address { get; set; }
15: public string City { get; set; }
16: public string State { get; set; }
17: public string PostalCode { get; set; }
18: public CustomerType TypeOfCustomer { get; set; }
19: public List<string> Messages { get; set; }
20:
21: public enum CustomerType
22: {
23: Bronze,
24: Silver,
25: Gold,
26: Platinum,
27: Adamantium
28: }
29: }
30: }
B. Get your Xsd on.
Use the Microsoft-provided xsd.exe utility to create your Xsd file. Or hey, roll your own if that's your thing. Whatever.
Sample command:
"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\x64\xsd.exe" C:\Zen\Zendoodle.dll /o:C:\Zen\Schemas
1: <?xml version="1.0" encoding="utf-8"?>
2: <xs:schema xmlns:tns="http://zendoodle.com/messaging/XML-Schema/2009" elementFormDefault="qualified"
targetNamespace="http://zendoodle.com/messaging/XML-Schema/2009" xmlns:xs="http://www.w3.org/2001/XMLSchema">
3: <xs:element name="Customer" nillable="true" type="tns:Customer" />
4: <xs:complexType name="Customer">
5: <xs:sequence>
6: <xs:element minOccurs="0" maxOccurs="1" name="Name" type="xs:string" />
7: <xs:element minOccurs="0" maxOccurs="1" name="Address" type="xs:string" />
8: <xs:element minOccurs="0" maxOccurs="1" name="City" type="xs:string" />
9: <xs:element minOccurs="0" maxOccurs="1" name="State" type="xs:string" />
10: <xs:element minOccurs="0" maxOccurs="1" name="PostalCode" type="xs:string" />
11: <xs:element minOccurs="1" maxOccurs="1" name="TypeOfCustomer" type="tns:CustomerType" />
12: <xs:element minOccurs="0" maxOccurs="1" name="Messages" type="tns:ArrayOfString" />
13: </xs:sequence>
14: </xs:complexType>
15: <xs:simpleType name="CustomerType">
16: <xs:restriction base="xs:string">
17: <xs:enumeration value="Bronze" />
18: <xs:enumeration value="Silver" />
19: <xs:enumeration value="Gold" />
20: <xs:enumeration value="Platinum" />
21: <xs:enumeration value="Adamantium" />
22: </xs:restriction>
23: </xs:simpleType>
24: <xs:complexType name="ArrayOfString">
25: <xs:sequence>
26: <xs:element minOccurs="0" maxOccurs="unbounded" name="string" nillable="true" type="xs:string" />
27: </xs:sequence>
28: </xs:complexType>
29: </xs:schema>
C. From Xsd to .java - Into the Breach!
The Java utility for working with schemas is xjc.exe. Actually, as with all things Java, there are at least 835,234 different ways of doing this. This is just how I do it. YMMV.
Sample command:
"C:\Program Files (x86)\Java\jdk1.6.0_12\bin\xjc.exe" -verbose C:\Zen\Schemas\schema0.xsd -p com.zendoodle.customer
This will generate .java source code classes. Which is great, but you must make one modification! And that is to identify the XmlRootElement by name. I've highlighted the two lines of code that you have to add below in bold red.
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.3 in JDK 1.6
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2009.05.04 at 08:59:01 PM EDT
//
package com.zendoodle.customer;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlRootElement;
/**
* <p>Java class for Customer complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="Customer">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="Name" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="Address" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="City" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="State" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="PostalCode" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="TypeOfCustomer" type="{http://zendoodle.com/messaging/XML-Schema/2009}CustomerType"/>
* <element name="Messages" type="{http://zendoodle.com/messaging/XML-Schema/2009}ArrayOfString" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlRootElement(name="Customer")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Customer", propOrder = {
"name",
"address",
"city",
"state",
"postalCode",
"typeOfCustomer",
"messages"
})
public class Customer {
@XmlElement(name = "Name")
protected String name;
@XmlElement(name = "Address")
protected String address;
@XmlElement(name = "City")
protected String city;
@XmlElement(name = "State")
protected String state;
@XmlElement(name = "PostalCode")
protected String postalCode;
@XmlElement(name = "TypeOfCustomer", required = true)
protected CustomerType typeOfCustomer;
@XmlElement(name = "Messages")
protected ArrayOfString messages;
/**
* Gets the value of the name property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = value;
}
D. Compile/JAR.
Last thing you have to do for the setup is to compile the .java classes into .class files, and then pack them into a .jar file. This is so that your set of .class files can be easily referenced. Include the .jar file in the Build Path of the Java application.
Sample command:
"C:\Program Files (x86)\Java\jdk1.6.0_12\bin\javac.exe" com\zendoodle\customer\*.java
"C:\Program Files (x86)\Java\jdk1.6.0_12\bin\jar.exe" cfv customer.jar com\zendoodle\customer\*.class
Pause
After that, you should be able to move objects with their data back and forth between .NET and Java. And for crying out oud, if you're ever going to do this more than once, automate it!
Next time we'll take a look at the queue, and how all the pieces will fit together. If you love weird and nifty stuff, see you then!
Saturday, February 21, 2009
Setup of a Drools development environment is fairly straightforward. (For a Java app.) For this exercise, I'm going to kick open Microsoft Virtual PC 2007, and start with a new instance of Windows XP Pro SP3.
First, install Java. Go to the Get Java link, and install the latest version, which at the time of this writing is Version 6 Update 12. Depending on your browser settings, you might have to download the file (jxpiinstall-6u12-fcs-bin-b04-windows-i586-17_jan_2009.exe) and run it locally. Whatever. The point is to step out and get Java on your machine.
Second, install the Eclipse IDE for Java EE Developers. It's 163Mb, and I must say a very nice and robust IDE. It has several nifty features that I wish Visual Studio had.
Here's something of a surprise. It's an xcopy deployment. You download the file, unzip it, and copy it to where you want it to run. I created a C:\Program Files\Eclipse directory, and placed it there. I also create a Desktop shortcut and also pin the shortcut to the Start menu.
The first time you run Eclipse, it asks you to designate a workspace. The workspace is your projects folder. Then you get the welcome page. There is an Overview, What's New, Samples, Tutorials, and the Workbench. The Workbench is, unsurprisingly, where you do the work.
Next, time to get a rules engine.
Drools is part of the jboss 'galaxy of applications'. jboss is probably most famous for their Application Server, which I hear is quite popular in some development communities. jboss is a division of Red Hat, and you can see a nice graphical overview of their many projects here. But I don't need all that stuff, of course, I'm just interested in the free rules engine. I should note that you can get enterprise-level support agreements from Red Hat for Drools.
Navigate to the Drools download page, and you'll see a few versions of Drools there. I'm going to download 5.0.0.M5, or Version 5 Milestone 5, and use that. There are nine files available; I just download them all. Broadband is awesome.
From drools-5.0.0.M5-eclipse-all, take the four files from the plugins subdirectory, and copy them to the Eclipse plugins folder. Mine is at C:\Program Files\Eclipse\plugins\.
Next from drools-5.0.0.M5-eclipse-all, take the three subdirectories under features and copy them to the Eclipse features folder. For me that's C:\Program Files\Eclipse\features\.
Then restart Eclipse, and go to the Workbench. Right-click in the Project Explorer, and select New... Project. You'll get a wizard, with the first dialog being a listing of all the possible project types, and Drools should be listed, as below:

Select the Drools Project type. Click Next. Type in a Project name; I used DroolsApp1. Next. Next. Ah, here we are at the Drools Runtime dialog.
There's No Drools Runtime Like My Drools Runtime.
The Drools Runtime can be defined as: the set of jar files necessary to run Drools. Straightforward, right? Eh, in a word, no. There are numerous ways you can assemble this set of files, depending on how you intend to configure your production deployment and the specific set of functionality you intend to provide your users. For example, if you are never going to allow your users to load in rules from Excel spreadsheets, then you don't need jxl-2.4.2. If you are only going to be using the DRL to define rules, and you won't be storing rules in Xml files, then you don't need xml-apis-1.0.b2. Yeah, baby, that's the love in Javaland. It's all up to you. These dependencies are outlined in the README_DEPENDENCIES.txt file.
What I recommend for this exercise is simple, however.
Go back to the files we downloaded from jboss.org. We'll be using drools-5.0.0.M5-bin.zip. Extract that, and place it somewhere on the file system. I put it at C:\drools-5.0.0.M5-bin\.
Take all the files in C:\drools-5.0.0.M5-bin\lib\*.* and copy them up to C:\drools-5.0.0.M5-bin\*.*. That'll work for now.
Back to the show...
The first time you create a Drools project in Eclipse, it asks where the Drools runtime is located. You'll need to provide that.
In the project wizard, click on the Configure Workspace Settings... link. It will open the Eclipse preferences pane where you specify the location of the Drools runtime. You can actually have a listing of multiple runtimes, and select different ones for different projects. I just have the one runtime. I name it Drools M5 Runtime and browse to C:\drools-5.0.0.M5-bin. Check the box. Finish out of the wizard.
And voila. You should have DroolsApp1 in your Eclipse Project Explorer. It should look like this:

Run it by hitting Ctrl+F11, or click the little green right arrow. If it asks, run it as a Java Application. Or you could click Alt+Shift+X, then J. Seriously.
You should see the output in the Console pane at the bottom of your IDE. If it says "Hello World {CR}{LF} Goodbye cruel world" then congratulations. You are now a rules engine developer. Immediately raise your rate by 9.35%.
Next post will take a closer look at the elements of this sample app, and postulate how the overall enterprise might look.
Link for future reference: Drools home page.
So I admit to you right from the start: this is something of an odd journey to undertake. Speaking with colleagues over the years, my own experience is that most developers raise an eyebrow and cast a wary eye toward anything labeled a 'rules engine'. And in fact, it does take a very specific set of requirements to lead to the conclusion that a rules engine is appropriate.
This dude and this other dude supply a good summary of why an organization might decide on going with a rules engine.
So once you decide a rules engine is an appropriate solution, and you pencil that into the sketch of the enterprise, what next?
The big dogs in the Business Rules Management System space cost real money. I'm talking Aston Martin money. And they're very nice, with bells and whistles galore. And if your budget can handle it, then you'll want to check them out. (Here's a hint. There's no shopping cart and checkout page on their web sites.)
But where's the fun in that? Let's look at the free stuff. While my career has been solidly grounded in Microsoft technologies, I'm willing to look to open source for solutions where it makes sense. And besides being a very robust and performant ReteOO-based rules engine, Drools happens to be free.
So this series, over the course of the next 20-something blog posts, will document this entire journey step by step. It begins with no pre-requisites, and will end with a Drools rules engine as part of a .NET enterprise solution, being called by multiple .NET and Java applications, all while running on the Windows platform.
I think it'll be fun.
Thursday, September 25, 2008
I was looking for an incoming fax service, and found this site, which offers incoming fax and a few other nifty things, for free. I can't say the incoming fax is business-grade reliable (yet) as they're still working out the kinks, but I hope they can get it all sorted out because the concept is really groovy. Check them out at http://drop.io.
eFax still offers a free incoming fax service, but you have to use their software to read the faxes. It's located here: http://www.efax.com/efax-free
This is why the Internet is cool.
Monday, September 22, 2008
I'm still lovin' the MacBook Pro, and having fun with it. However, there's one thing that I didn't expect, and that was the surprisingly noisy slot-loading optical drive. The first time I loaded a disc into it, it went Snap! Izzz! Whirrr! CLICK! Snap! I honestly wondered if it had cracked the disc in half. Was I going to have to pick out the pieces of a shredded DVD with needle-nose pliers? But no --- this is a feature. The other slot-loaders I've had, mostly CD players, load a disk is near silence, with perhaps only a muted click, and soft spin-up. (But then, perhaps the violent snapping noises enable super-precise positioning for ultra-accurate DVD burning and reading. How have other drives performed for all these years without them? Who knows?)
What I do know is that Apple actually posted the sounds of the MacBook Pro. So you can listen before you buy. Now that's thinking different.
First, a brief historical interlude. My first paying job in the computer industry was at a computer retailer in Tampa, Florida. It was a small company with eleven employees, two store locations, and we built and sold clones, set up small networks, and enjoyed the high margins that a hardware retailer could get (20% and up!) back in the early 1990s. Like at many small companies, we all did it all, and wore every hat there was to wear. It was a fabulous time in the industry, and I developed an affinity for hardware tech. I never got tired of building machines and troubleshooting hardware issues. And even after many years now, I still love the hardware and still build my own rigs.
I’ve gone through a number of notebook computers, and for me, the first question to consider when buying a notebook is: Do I want a smaller notebook with long battery life, or do I want big screen and horsepower (with the understanding that battery life might equal 25 minutes)?
My last notebook was a big Sony Vaio. I made the decision that I wanted something in the 'desktop replacement' class, and it was heavy, large, and battery life was around 30 minutes. and while I really liked the Sony hardware, the overall experience I had with the notebook was miserable. The notebook came with no disks at all, and so I had to burn my own driver-backup disks. Yuk. Plus, when I actually needed them, months later, the disks didn’t work, and I had to call up Sony, where they cheerfully told me that I could order a set of disks for $99. Nice. Anyway, I used that notebook for a year and a half, sold it, and was 'without notebook' for a while.
Last week, I decided it was time to get portable again. I wanted something smaller this time, but still with enough juice for Visual Studio. I had heard from quite a few developers that really liked the MacBook Pro, running Boot Camp/VM Fusion/Parallels in order to load Vista and (the all-important aforementioned) Visual Studio). The machines certainly look cool, but is that enough to justify the premium? To check it out, I went to Best Buy and tinkered with all the notebooks . . . which is an enjoyable afternoon all unto itself. Then I plunked down my two large on the MacBook Pro 15.4" model. (My path to the dark side was complete!)
I must report that I really like this machine. Not to get existential, but Apple just gets it. After messing around with OS X, which is nifty, I partitioned the drive for Vista, installed that OS, and wondered how bad the driver situation would be. After installing Vista, I inserted the Apple CD, and Vista immediately recognized setup.exe, ran it, which installed the Boot Camp software on Vista, along with all the drivers - - - even the ones that control the keyboard backlighting. That’s just cool. Wifi works, Bluetooth works . . . it all just works. Dang, just like the slogan. Credit where credit is due: the boys from Cupertino design a good notebook.
For a mouse, I picked up the Logitech VX Nano. I use the MX Revolution when I code, and I just love the heavy, metal scroll wheel. That’s the best feature I’ve found yet on a mouse, and the VX Nano has a scroll wheel just like his big brother.
All in all, I am one extremely satisfied customer. Now I’m wondering if I’ll ever buy anything except an Intel-based Apple notebook. They rule.
And as a historical observation, the camps of Apple Fanboys and the camps of Microsoft Fanboys were once clearly delineated. It’s interesting that in recent years the lines of demarcation have blurred . . . to the point where Windows developers buy Apple notebooks to run Visual Studio on a Windows OS inside OS X to build code that gets deployed to Windows Server machines.
Wednesday, August 27, 2008
Like many developers, I spend quite a bit of my day RDP’ed into some virtual server or other. Even with dual monitors, it can become annoying to flip between sessions. So then I got a tip about this very nifty utility, and now I couldn’t get along without it.
Made by visionapp, it’s called vRD. They have a free version, and one that’s $69.00, or slightly more if you want upgrade maintenance & support. I use the freebie.
You can store your credentials if you want to, categorize your server list in a nice treeview, and the app presents your sessions in a really nice tabbed interface...
Good stuff.
http://www.visionapp.com/141.0.html
Scroll to the bottom; you’ll see a listing for visionapp Remote Desktop (vRD 1.5) - Freeware. Registration is required.
Disclaimer: Not affiliated in any way with visionapp. They don’t even know me.
Wednesday, August 13, 2008
Use the very nifty SQL_VARIANT_PROPERTY to determine the data type of a returned column.
Admittedly, it’s faster to look at the table definition in SSMS. But this is pretty neat.
DECLARE @TableVar TABLE (MyColumn numeric(18,5))
INSERT INTO @TableVar VALUES (5.5)
SELECT TOP 1
MyColumn,
SQL_VARIANT_PROPERTY(MyColumn, 'BaseType') AS 'Base_Type',
SQL_VARIANT_PROPERTY(MyColumn, 'Precision') AS 'Precision',
SQL_VARIANT_PROPERTY(MyColumn, 'Scale') AS 'Scale'
FROM @TableVar
|