Monday, February 28, 2005

Rules Engine III

Thanks to Jon Flanders at Developmentor for answering my Rule Engine query. The answer is to use the "update" action to reassert Fact2 once it has been updated, and to then add in a second predicate to the first rule to prevent the policy from entering a recursive loop.

So:
Rule1: If Fact1 == Y and Fact2 != Y then Fact2 = Y; Update Fact2;
Rule2: If Fact2 == Y then Fact3 = Y;

There are a couple of issues that I have with this:

1. The need to include the Fact2 != Y predicate explicitly seems incorrect to me - I would have thought that the rules engine's evaluation and agenda building should have worked that out itself, and prevented the loop?

2. The above concern, together with the need to explicitly reassert Fact2 mean that rule creation has just crossed a critical boundary - and I challenge anyone to find me a business analyst who would feel comfortable with this scenario. All the vocabularies in the world will not make rule creation a BA-friendly activity if they are required to understand the internal workings of the rule engine.

Data deletion

There's been a bunch of articles in the press recently about privacy concerns, data being left on old computers, etc, etc. Most of these have mentioned expensive 'cleaning' tools for wiping hard drive contents, and they often mention the need to overwrite empty segments a number of times to garuantee their deletion.

There is a DOS command that will do this for you - I *think* it's post SP1 for XP. It's called cipher, and it overwrites blank segments three times - first with 0, then with 1, then with random numbers. Use the "/w" option.

Thursday, February 24, 2005

Snowy weather

The prevailing weather conditions (snow, snow, sleet, sleet, snow) have coincided with the arrival of the equipment list for my next holiday.
It includes snow shovel, avalanche probe and transceiver!

Rules Engine investigations

This is a copy of my recent posting to the newsgroups, which I'm posting here in case anyone has a simple answer to what I believe is a simple question...

------------------------------------

I have created a simple policy of two rules, that operate on a single TypedXmlDocument:

<ns0:Root xmlns:ns0="http://RulesEngine.Schema1">
<Fact1>Y</Fact1>
<Fact2>N</Fact2>
<Fact3>N</Fact3>
</ns0:Root>

I want this to work in such a fashion that when testing the rule with the aforementioned sample, I end up with a message with all facts = Y.

My rules are:
1. If Fact1 = Y then set Fact2 = Y
2. If Fact2 = Y then set Fact3 = Y


Stephon Mohr's chapter on the subject states:
"When the available facts exist to evaluate a rule's condition and it evaluates to true, the rule is fired. As rules fire, new facts are asserted into memory. For example, firing a rule might cause a field to be set in a message. This becomes a new fact in memory, which may cause another rule to fire. This continues until no more rules can fire."

I tested the policy, and got the following results:

RULE ENGINE TRACE for RULESET: Policy1 24/02/2005 15:12:56

FACT ACTIVITY 24/02/2005 15:12:56
Rule Engine Instance Identifier: d54d5da0-b88a-4e94-ba09-88932c880c92
Ruleset Name: Policy1
Operation: Assert
Object Type: TypedXmlDocument:Schema1
Object Instance Identifier: 735

FACT ACTIVITY 24/02/2005 15:12:56
Rule Engine Instance Identifier: d54d5da0-b88a-4e94-ba09-88932c880c92
Ruleset Name: Policy1
Operation: Assert
Object Type: TypedXmlDocument:Schema1:/Root
Object Instance Identifier: 725

CONDITION EVALUATION TEST (MATCH) 24/02/2005 15:12:56
Rule Engine Instance Identifier: d54d5da0-b88a-4e94-ba09-88932c880c92
Ruleset Name: Policy1
Test Expression: TypedXmlDocument:Schema1:/Root.Fact1 == Y
Left Operand Value: Y
Right Operand Value: Y
Test Result: True

AGENDA UPDATE 24/02/2005 15:12:56
Rule Engine Instance Identifier: d54d5da0-b88a-4e94-ba09-88932c880c92
Ruleset Name: Policy1
Operation: Add
Rule Name: Rule1
Conflict Resolution Criteria: 0

CONDITION EVALUATION TEST (MATCH) 24/02/2005 15:12:56
Rule Engine Instance Identifier: d54d5da0-b88a-4e94-ba09-88932c880c92
Ruleset Name: Policy1
Test Expression: TypedXmlDocument:Schema1:/Root.Fact2 == Y
Left Operand Value: N
Right Operand Value: Y
Test Result: False

RULE FIRED 24/02/2005 15:12:56
Rule Engine Instance Identifier: d54d5da0-b88a-4e94-ba09-88932c880c92
Ruleset Name: Policy1
Rule Name: Rule1
Conflict Resolution Criteria: 0

FACT ACTIVITY 24/02/2005 15:12:56
Rule Engine Instance Identifier: d54d5da0-b88a-4e94-ba09-88932c880c92
Ruleset Name: Policy1
Operation: Retract
Object Type: TypedXmlDocument:Schema1
Object Instance Identifier: 735

FACT ACTIVITY 24/02/2005 15:12:56
Rule Engine Instance Identifier: d54d5da0-b88a-4e94-ba09-88932c880c92
Ruleset Name: Policy1
Operation: Retract
Object Type: TypedXmlDocument:Schema1:/Root
Object Instance Identifier: 725

-------------------------------------------------------

According to my reading of forward chaining, Rule 1 should have been fired, changing the value of Fact2 to 'Y', which should have caused Fact2 to be reasserted, which in turn would cause Rule 2 to be fired on the second pass, resulting in Fact 3 being set to Y.

I also don't understand why the output shows the facts that are asserted and retracted are given as:

Object Type: TypedXmlDocument:Schema1
Object Type: TypedXmlDocument:Schema1:/Root

What about the actual elements Fact1 and Fact2 - aren't they are what I'm evaluating?

Rules Engines

I've been trying to get to grips with the Rules Engine today, and having some difficulty getting my head around the world of Forward Chaining Inference Engines, which is apparently what the BizTalk rules engine implements. Or not...

My investigations led me to this extraordinary posting, which has opened my eyes to a whole world I never knew existed. Both Scott Woodgate and Stephen Mohr (of BizTalk Unleashed fame) get involved, and Mr. Lin has firmly established his reputation as the web's greatest pedant.

(Not for the faint-hearted.)

Friday, February 18, 2005

Zermatt

In keeping with my new year's resolutions 3 & 4, I've just come back from a week in Zermatt. Skiing was fantastic, snow in great condition, weather so-so, and all-in-all a great break.

Zermatt is so picturesque it feels like a film set, and although the skiing isn't so extensive, it was more than enough for 5 days. We even managed a grand dinner in celebration of the 140th anniversary of Edward Whymper's first ascent of the Matterhorn, his account of which is a must-read for anyone interested in Alpine mountaineering.

I now have 5 weeks to get in shape for the next one :-)

Monday, February 07, 2005

If...Then...Else

A common operation within maps is to inject a default value into the output schema if the the input field is blank / missing, otherwise just copy over the value.

This is a bit of a nightmare using the standard Logical Existance functoid, and is much more easily accomplished using inline C#. Simply added a script functoid, connect the input field as the first parameter, add a second parameter set to the default value, then use the following function:

public string IfThenElse(string param1, string param2)
{
return (param1 == null || param1.Length == 0) ? param2 : param1;
}

Then simply connect the output of this script functoid to your output field.

Thursday, February 03, 2005

BizTalk PowerToys

There's an excellent list of downloadable BizTalk utilities here. I'm particularly interested in the BizTalk Configuration Documenter, and I'll report back on my findings here.

Social Hacking

Quite elegant piece of social hacking here - and from an 11 year old!

Wednesday, February 02, 2005

New msn.com

When I first registered XMLSpy (3.5) it asked me whether all HTML files would be XHTML compliant. That was about 5 years ago, so it's taken some time, but I can now confirm that, slashdot moans aside, msn.com is at least now valid XML.

I predict minor upturn in screen-scraping as an integration technique.

[/. isn't btw]

Tuesday, February 01, 2005

Delivery notifications

A couple of links from Kevin Smith's blog re. delivery notifications:

TimeSpan.Parse() and the Delay shape

When using configurable delays (defined in the .config), I began by assuming that we would always implement delays in days, as we were working with 6 week schedules. I was then asked if we could compress 6 weeks of schedule into a single day, for testing, meaning that I now had to specify the delay in hours. I then spent some time coming up with a clever way to parse config strings to provide maximum flexibility (e.g. to allow delays of days, or seconds, and everything in between.)

It then twigged that the TimeSpan class probably already has a Parse() method (as DateTime does.) It does, and it accepts all manner of useful input.

Details of the input string format here.

Orchestration Scheduler

A nifty way of forcing activation of an orchestration at a given time is to use the SQL adapter to poll a table, in combination with a service window that restricts the poller to fire only once per day.

Create a table that contains any information you might want in your orchestration (i.e. the command message data), then create a SQL receive location that polls this table once a day, and set the service window to open at the time you want the orchestration to fire.

If you set the service window to start and stop at the same time, it is actually open for one minute - the start opens the window at hh:mm:00 and the stop ends the window at hh:mm:59, so as long as you set the poller frequency to > 1 minute, it will only fire once per day.)

You can put all sorts of information in the table, and build up quite complex schedules, even forcing multiple orchestrations to start thereby implementing a multi-threaded scheduler. This also allows you to keep track of the last time a poller was started. It's potentially quite a powerful technique.

Suspended Queue Listener

I keep on losing track of other people's useful posts, so I'm going to start keeping them here.

There is a WMI event that is fired when messages are suspended - see here for a full implementation of a suspended queue listener from Martijn Hoogendoorn.

BizTiVo

Further notes on the subscription issue - the more I read on the newsgroups, the more I appreciate how important the pub-sub model underlying BTS is to understanding problems with messaging.
I spent a day with some developers just starting out with BTS last week, and I found that showing the SubscriptionViewer application whilst enlisting and unenlisting orchestrations and send ports was invaluable in attempting to explain BizTalk's murky interior.

This is an extract from a recent posting to a query about messages being suspended (unresumable) when the matching CBR send port is unenlisted, and why they won't resume when the port is re-enlisted.

(Ok, so it's my own answer, but if I can't quote myself on my own blog, where can I?)

"The subscription required for the message to be processed is created when the [send] port is enlisted. When the receive location picks up the message, it is delivered to the messagebox, where the message agent runs through the subscription table to see if there are any services subscribing to the message.

If not, it is marked as suspended (unresumable). If there is a subscriber, but it is stopped, then the messages is suspended (resumable.) Restart the send port, and the message should clear.

If the send port was not enlisted, then there will have been no available subscriber for the message when it arrived, so BizTalk cannot process it. It is actually quite logical to suspend these messages and terminate the pipeline, as the alternative would require BizTalk to save every single message it ever received, on the premise that someone might at some point want to subscribe to it.

It's a bit like TiVo - you can pause live tv, but you can't go back to a show that was on last week if you didn't record it!"

BizTalk Configuration

Another one for the bookmarks. Configuration is an issue with BTS because of the distributed nature of the product, and the management problem of having multiple conifg files. We've experimented with both Rules and config files, and whilst the former works extremely well, we've actually settled on the latter (we only have 2 boxes in production, so deployment is less of an issue for us).

Either way, this is a good discussion of the problem.