Dana Stevens

Ruminations of a software developer.
posts - 8, comments - 370, trackbacks - 0

Tuesday, May 05, 2009

Drools on Windows (Part 3 of 22) - Object Interop

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>
 * &lt;complexType name="Customer">
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="Name" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
 *         &lt;element name="Address" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
 *         &lt;element name="City" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
 *         &lt;element name="State" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
 *         &lt;element name="PostalCode" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
 *         &lt;element name="TypeOfCustomer" type="{http://zendoodle.com/messaging/XML-Schema/2009}CustomerType"/>
 *         &lt;element name="Messages" type="{http://zendoodle.com/messaging/XML-Schema/2009}ArrayOfString" minOccurs="0"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/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!

 

posted @ Tuesday, May 05, 2009 7:13 PM | Feedback (31) | Filed Under [ Drools Java ]

Powered by:
Powered By Subtext Powered By ASP.NET