Saturday, 29 May 2010

Madura Rules part 1

My earlier posts described Madura Objects, which is a way to define Java objects that automatically call a validation engine whenever they change. A valid change is accepted and an invalid one is rejected, leaving the state of the objects unchanged (ie still valid). The objects are just POJOs with an added interface and one method used for fetching metadata. They are all generated using JAXB with a plugin, so you don't have to write any of the code to do all this.

But so far this only handles single field validation, relationships between fields cannot be described. So you can say a string field must be no more than 20 characters long and maybe has to look like an email address. But you can't say if the customer type field is "A" then the business type must be "Ag". Nor can you say there must be no more than n items in a list.

The way to manage this is to add a rules engine to the Madura Objects validation engine. I have implemented this as a plugin because, though I might think my own rules engine is the greatest, other people might want to implement their own. Also I'm not yet certain if I will open source the rules engine so I need to keep it separate from the open source Madura Objects.

What do the rules look like?

rule: Customer "Determine business from customerType"
{
  if (customerType == "A")
  {
    business = "Ag";
  }
}

This is a classic rule in that it has a condition and an action. Multiple actions are fine, but there's only one in this example. The syntax intentionally looks like Java. We have a Customer object and we want to ensure that if we set the customerType field to "A" the business field will be set to 'Ag'. Remember this happens automatically. It is probably obvious enough but the 'Customer' just after 'rule:' means the fields 'customerType' and 'business' are fields on the Customer object.

It is worth noting that if there is already a value in 'business', and it is different, then this rule will throw a constraint violation exception and roll back the last change.

constraint: Customer "check the count" "No more than 10 invoices"
{
  !(invoiceCount > 10);
}

This kind of rule has just a condition, no action. The condition must always be true. So, after any relevant change this rule is checked. If it fails the change is rejected and rolled back. In this case we might have invoiceCount derived from counting the number of invoices attached to this customer. Attaching the 11th invoice would be ejected by this rule. We can attach a message to this rule, "No more than 10 invoices" which is returned in the exception that is thrown.

formula: Customer "figure the invoice count"
{
  invoiceCount = count(invoices);
}

This is a formula rule, basically an algebraic statement that is aways enforced. This is how we figured the invoiceCount we used in the constraint rule. Yes, we could have combined the previous example and this one with a more complex condition, but that would not make such a good example.

With these rules slipped behind the validation engine you can perform complex validations as well as derive new values. New values that are deemed inconsistent with what has already been supplied are rejected using an exception. The inconsistent value is rolled back.

In my next post I will describe how this is configured.

Wednesday, 19 May 2010

New Headset

This replaces the headset I blogged about here.

The old headset suddenly stopped playing any base and went all faint. No, it isn't my hearing, just not enough sound. It is still under warranty so I considered calling that in, but actually I am sick of the way it doesn't stay in my ears when I walk, so I am constantly adjusting it. So, I got a new one, a different one. I got a Sony DR-BT21G, which is the sort that wraps around the back of my head and has pads over the ears rather than plugs that (are supposed to) stick inside my ear holes.

I've had it a few days and I'm quite happy with it. Things worth noting, though.
  • The instructions say to push in one of the buttons to pair it. I though it wasn't working at first because you have to hold that button down for quite a while before it takes. Don't give up too soon.
  • When I went walking the music skipped badly. The instructions say that when this happens it means it is trying to use a high bit rate and interference (various other radio sources) is messing the signal. I was able to switch to a lower bit rate and now it is fine, the odd skip, but not a problem.
  • The around the back of the head style takes a little getting used to. There's a slight inward pressure on each side of my head and that gave me a headache the first day. I've been working up to longer and longer with it and now it seems fine. So just something to get used to.
Other than those, the music sounds fine, and it manages calls perfectly well. It is generally comfortable and easy to drive. I think it is mostly invisible too, in spite of the ear pads, because my hair is long enough to cover it. That means when I am out and about and talking on the phone people assume I have 'the voices'. Maybe I do. Maybe I don't actually get any real calls. Works for me.

Thursday, 13 May 2010

Hibernate Mapping

Hibernate is such a cool product. I've been using it a few years now but I was a bit slow starting because I didn't connect the name with the function. I mean, something to do with going to sleep? Never mind it is excellent. Just in case you're still wondering what it is Hibernate lets you work with Java objects and looks after saving and fetching those objects to/from a relational database. But you probably knew that.

Naturally there are ways to map the database tables against the Java objects and, while this can be simple enough, sometimes it is complex and today was one of those times.

The problem I hit today concerned an existing (think legacy) database. I really wanted to avoid changes to the db structure, or even the data. The area of interest concerned two objects: ProdCatalog and ProdCatSection. ProdCatSection extends ProdCatalog.

These both map to the same table. Now, Hibernate handles this nicely enough. You define a discriminator column and have two discriminator values, one for each object, so Hibernate knows how to instantiate the objects from the row. All the examples I found for this assumed there was a common super class that two concrete classes extend, but if you have two concrete classes like I have it works just fine.

I put this in the top of the ProdCatalog class definition:

@Entity
@Table(name = "PROD_CATALOG", schema = "PRODUCT2")
@DiscriminatorValue(value="ProdCatalog")
@DiscriminatorColumn("recordType")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class ProdCatalog implements java.io.Serializable,ProductCatalogMember {

In the ProdCatSection I only need this:

@Entity
@Table(name = "PROD_CATALOG", schema = "PRODUCT2")
@DiscriminatorValue(value="ProdCatSection")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class ProdCatSection extends ProdCatalog

That would work... except that there is no recordType in the table. No, the guys who put this database together decided to keep the discriminator in another table, called PROD_CAT_STRUCTURE.

Even worse, this doesn't have one simple field. There is a column in PROD_CAT_STRUCTURE that may be null, indicating we have a ProdCatalog and not null indicates a ProdCatSection. There can be multiple records in the join as well.

Now, Hibernate does not seem to have a way of saying @DiscriminatorValue(value=null) and, anyway, I need a null and and 'anything else'.
The answer is to use the DiscriminatorFormula

@DiscriminatorFormula("case when exists (select 1 from PROD_CAT_STRUCTURE pcs
where pcs.CAT_ID = CAT_ID and pcs.CAT_ID_PARENT is null)
then 'ProdCatalog' else 'ProdCatSection' end")

The formula is just SQL (Oracle's dialect in this case) and this formula will return ProdCatalog or ProdCatSection depending on the result of the query. I could test this using my usual SQL tools to verify the query was valid (though I had to edit a literal into the second CAT_ID for that).

Now that the formula (rather than DiscriminatorColumn) is being used we have the right values coming back and the DiscriminatorValue annotation can work. The names I chose for these can, of course, be anything at all, but it made sense to me to use the object names I hoped to create. The actual requirement is that the results of the formula matches the DiscriminatorValue values. The formula only needs to go on the ProdCatalog class.

Part of the exercise of getting this working involved generating the classes using the Hibernate tools, specifically the Eclipse plugin. I have had trouble installing this in the past and went abut it with a bit more determination than before. I'm using Eclipse 3.5 (Galileo). Invoking the update manager (help->install new software) seemed to work but, once it had finished, there was no sign of any Hibernate in my Eclipse workspace.

So I did the download and unzip approach. The version I used was 3.2.4.v200910211631N-H194-GA and that worked just fine.

Sunday, 9 May 2010

Serializing XML

I am trying to output an XML Document (org.w3c.doc.Document) from Java. I always forget how to do this, somehow it doesn't work with the way I think. So I googled and found this code:

TransformerFactory factory =
TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);

But this gave me a NullPointerException down in the org.apache.xml.utils.TreeWalker.
Huh? I seemed to recall that there was a better way to do this than calling a dummy xsl transform, which is what the above code does.
A bit more searching and I found the method I've used previously:

XMLSerializer serializer = new XMLSerializer();
serializer.setOutputByteStream(System.out);
serializer.serialize(doc);

And that works fine. It seems there is a bug in the tree walker class triggered when text nodes are empty. Not much detail but I found it here.

Friday, 7 May 2010

Madura Objects part III

Last entry I explained how, when using Madura Objects, you generate your Java Beans from an XSD file. The resulting classes have code injected into them by the Madura Objects JAXB plugin so that they validate automatically when the setters are called.

Madura Objects injects other things as well, notably metadata. With simple Java objects you don't have much in the way of metadata. You have the field name, type and current value and that's about it. Now that Java has annotations you can attach more static information to the field. Madura Objects uses annotations to define the validation data as well as the label. It generates code like this:
    @Label(labelName = "xxx")
    @Description(name = "this is a description")
    @Regex(pattern = "a*b")
    @Length(minLength = "0", maxLength = "30")
    public String getName() {
        if (m_validationSession!= null) {
            m_validationSession.clean(this);
        }
        return name;
    }

The Regex and Length annotations here drive the validation engine in Madura Objects. You can see a little of the generated code in the getName() method. Other validation related annotations are Digits, Email, Range and BeanValidator. The last can specify some custom Java code you can inject into the validator engine.

But it is not just about validation. The Label annotation is, fairly obviously, something a UI might use to paint next to the rendered field. There are others which declare the field to be read only, inactive (suggesting it ought not to be displayed), required etc. Description can be used for documentation or help text.

Remember these are all specified in the XSD file that generated this Java. You don't have to edit them into the classes. In fact you really must not edit these files because next time you generate they will be overwritten. So how did we specify the label and description in the XSD?
<element name="name">
    <xsd:annotation>
        <xsd:appinfo>
            <annox:annotate>
                <md:Label labelName="xxx"/> 
                <md:Description name="this is a description"/> 
            </annox:annotate>
        </xsd:appinfo>
    </xsd:annotation>
   <simpleType>
        <restriction base="string">
           <maxLength value="30"></maxLength>
            <pattern value="a*b"></pattern>
        </restriction>
    </simpleType>
</element>

I've used the annox tool to help out here. This is another JAXB plugin which grabs my reference in the XSD and turns it into an annotation. Annox comes from the same people who produced HyperJAXB3. In practice this is all looked after transparently during the generation of the Java objects.

Another important bit of metadata we need is a list of valid values. We can do this two ways. The first way is just the 'normal' way expected by JAXB by itself. This looks like this:
<element name="business" type="tns:IndustryType"/>
...
<xsd:simpleType name="IndustryType">
    <xsd:restriction base="xsd:string">
        <xsd:enumeration value="Ag"/>
        <xsd:enumeration value="fish"/>
        <xsd:enumeration value="finance"/>
    </xsd:restriction>
</xsd:simpleType>

In this example we defined a field called business and pointed it at a simple type definition with a list of values. Remember this is JAXB out-of-the-box. The resulting code is a Java class called IndustryType, which is an enum, and a field that looks like this:
@Enumerated(EnumType.STRING)
public IndustryType getBusiness() {
    if (m_validationSession!= null) {
        m_validationSession.clean(this);
    }
    return business;
}

This, obviously, only accepts values from the enum which we know must be valid. The validation engine will check them anyway. This all works perfectly well as long as the list of values is quite static. To change the values you need to regenerate the Java.

If you need something more dynamic you can do this:
<element name="customerType">
    <xsd:annotation>
        <xsd:appinfo>
            <annox:annotate>
                <md:ChoiceList name="customerType"/> 
            </annox:annotate>
        </xsd:appinfo>
    </xsd:annotation>
    <simpleType>
        <restriction base="string">
            <maxLength value="30"></maxLength>
        </restriction>
    </simpleType>
</element>

The important bit to note is the ChoiceList entry. Here is the generated code:
@ChoiceList(name = "customerType")
@Length(minLength = "0", maxLength = "30")
public String getCustomerType() {
    if (m_validationSession!= null) {
        m_validationSession.clean(this);
    }
    return customerType;
}

Probably no surprises there. But the validation engine knows about the ChoiceList and uses that instead of an enum. I won't go into the Spring wiring that I use to arrange this (there are full examples in the project) but you create an XML document containing the choice lists and their contents. The file can be regenerated any time, making the valid choices easily revisable.

We can access this metadata very easily because the Madura Objects plugin generates the code in the classes to support it. The plugin adds the nz.co.senanque.validationengine.ValidationObject interface to the generated objects and this has a getMetadata() method which returns an ObjectMetadata object. This is just a wrapper for a list of FieldMetadata objects, and they describe the current metadata for the fields.

Yes, you could do this yourself using reflection. But the getMetadata() object is simpler and it also supports dynamic metadata. But dynamic metadata is a topic for next time. 

Monday, 3 May 2010

Madura Objects part II

I kept the previous post short because I know I never read long blog posts. So here is some more about Madura Objects. Recall that we generate Java using JAXB/XJC and that is injected with plugins. Our resulting classes are just beans... with some extra stuff.

Now, let's assume the XSD file you fed into XJC defined an object called Customer which has a field called name. The definition for name looks like this:
<element name="name">
 <simpletype>
     <restriction base="string">
          <maxlength value="30"/>
          <pattern value="a*b"/>
       </restriction>
   </simpletype>
</element>

This is just ordinary XSD stuff and it says that this field must be no longer then 30 characters and specifies a regex pattern the contents must conform to.

Okay, now we build a little code....
    Customer customer = new Customer();
    validationSession.bind(customer);
    boolean exceptionFound = false;
    try
    {
        customer.setName("ttt");
    }
    catch (ValidationException e)
    {
        exceptionFound = true;
    }
    assertTrue(exceptionFound);

All I did here was instantiate the Customer object (Customer.java was generated by XJC) and then bind it to the validationSession I'd created earlier. Then I attempted to set a value in the name. But the value does not pass the regex expression so I get an exception. The bind call will automatically bind to every object attached to Customer, including ones I add after the bind. So we don't need to bind very often. After the bind there is actually no API to remember. Just use the objects normally and handle exceptions.

If you instantiate an object, unpack it from XML using JAXB or fetch it from a database using Hibernate (all of which are easy to do with these generated objects) then you have to bind it. If you fetch from Hibernate make sure you don't use a lazy fetch because then the bind won't find the attached objects.

If you don't bind then the objects behave like normal beans, and this is sometimes just what you want.

Next time I'll blog about metadata.