[rules-users] Complex validation logic for hierarchies with Drools
Edson Tirelli
tirelli at post.com
Thu Jul 12 17:48:54 EDT 2007
Oleg,
As I mentioned to you, it is perfectly fine and easy to use the rules
engine to validate your object tree as long as you instruct your users that
they must write structured rules. What I mean is: as much as DSL templates
allow you to write rules that resemble natural language, it is not really
natural language. The main advice is to group objects and attributes
together. So, instead of writing the rule as:
3. "ServiceDescription" contained inside "ClientService" with type "BRONZE"
should has status "ACCEPTED"
They need to write the rule as:
3. If there is a ClientService whose type is "BRONZE" and a
ServiceDescription contained inside it whose status is different of
"ACCEPTED" then report error
As you can see, all the constraints/attributes are listed right after
each object type. The above rule can be translated to:
rule "3. Validate status for BRONZE"
when
There is a ClientService
- whose type is "BRONZE"
There is a ServiceDescription
- contained inside it
- whose status is different of "ACCEPTED"
then
report error
end
As you can see, the rule definition is very close to the actual rule, if
you take the appropriate care when writing it, having the
attribute/constraints right after each object type.
Now, the DSL mapping will transform the above rule into:
rule "3. Validate status for BRONZE"
when
cs : ClientService( type == "BRONZE" )
sd : ServiceDescription( this memberOf cs.children, status != "ACCEPTED"
)
then
# report error
end
When you try to extrapolate the above example to your real business
example, to make your DSL template completely generic, you may find the need
to explain to your users the concept of "variable" though.
So, what he would do is actually name each of your objects. Example
(replace X and Y for any identifier that makes sense for the user):
3. If there is a ClientService named X whose type is "BRONZE" and a
ServiceDescription name Y contained inside X whose status is different of
"ACCEPTED" then report error
If the user names each object, it will be much easier to write generic
templates, since your rule would become:
rule "3. Validate status for BRONZE"
when
There is a ClientService named X
- whose type is "BRONZE"
There is a ServiceDescription named Y
- contained inside X
- whose status is different of "ACCEPTED"
then
report error
end
And the DSL would translate that to:
rule "3. Validate status for BRONZE"
when
X : ClientService( type == "BRONZE" )
Y : ServiceDescription( this memberOf X.children, status != "ACCEPTED" )
then
# report error
end
I don't think that it is too hard to explain to users that they need to
name each of his objects and this adds a great flexibility to the rules when
adding constraints between objects of the same type.
The final (and hardest) problem you will face is that you mentioned that
your objects may be any level deep inside each other and you want to
abstract that from users. In this case I see only 2 options:
1. The first option is do what you are already doing and create a helper
function that goes deep a hierarchy checking for the existence of the
relationship.
2. The second option is to create a relationship object that will flatten
your tree structure transforming it in a pure relational structure. This is
a very common solution used in databases that do not support hierarchy
queries. The idea is that you create an object with attributes parent, child
and optionally the level (distance) between each other, and you assert a
copy of it for each related object in your object hierarchy (in
computational theory we call this set of objects the result of the
transitive closure calculation). The result is really a trade-off between
memory and query time. You need to check if for your use case, the
performance gains and expressiveness flexibility pays off the memory cost.
Hope it helps.
[]s
Edson
2007/7/12, Oleg Yavorsky <oleg_yavorsky at yahoo.com>:
>
> Hi.
>
> I've got a lot of domain objects represented as instances of classes
> generated from XSD using Castor. My goal is to implement validation
> framework for whole tree which contains complex "when" conditions (see
> bellow). Furthermore, rules definitions should be very easy for
> unexperienced user to change so I need DSL.
>
> Now I use reflection to assert whole tree of objects to working memory
> along with additional context information (like stack of parents associated
> with particular object). Then I use eval() in LHS to call boolean functions
> which performs checks in plain Java to see if object in particular context.
> But I think that this is ugly approach and it doesn't solve other cases. I'm
> new to Drools but something tells me that it can give me more elegant
> solution for such problems.
>
> Here is an example of possible hierarchy (used XSD to better represent
> it). Make note that in production case similar hierarchy is more complex and
> has a lot of objects. Sorry, but I don't know how to format it in email.
>
> <?xml version="1.0" encoding="UTF-8"?>
> <schema xmlns="http://www.w3.org/2001/XMLSchema"
> targetNamespace="http://www.example.org/ClientService"
> xmlns:tns="http://www.example.org/ClientService"
> elementFormDefault="qualified">
>
> <complexType name="ClientService">
> <sequence minOccurs="0" maxOccurs="1">
> <element name="ClientInfo">
> <complexType>
> <sequence>
> <element name="Name" type="string"/>
> <element name="AccountID" type="string"
> minOccurs="0" maxOccurs="1"/>
> </sequence>
> </complexType>
> </element>
> <element name="ServiceDescription" minOccurs="0">
> <complexType>
> <sequence>
> <element name="Name" type="string"/>
> <element name="Status">
> <simpleType>
> <restriction base="string">
> <enumeration value="VERIFIED"/>
> <enumeration value="ACCEPTED"/>
> <enumeration value="DENIED"/>
> </restriction>
> </simpleType>
> </element>
> </sequence>
> </complexType>
> </element>
> </sequence>
> <attribute name="Type">
> <simpleType>
> <restriction base="string">
> <enumeration value="BRONZE" />
> <enumeration value="SILVER"/>
> <enumeration value="GOLD"/>
> </restriction>
> </simpleType>
> </attribute>
> </complexType>
> </schema>
>
> And here are possible validation cases:
>
> 1. "ClientInfo" contained inside "ClientService" with type "GOLD" should
> have "AccountID" assigned.
> 2. "ClientService" with type "BRONZE" could have up to 3
> "ServiceDescription"
> 3. "ServiceDescription" contained inside "ClientService" with type
> "BRONZE" should has status "ACCEPTED"
> 4. "ClientInfo" should have "AccountID" assigned if there is
> "ServiceDescription" with name "SUBSCRIPTION"
>
> I'd like to come up with rules definition that looks like this (for 3-d
> example):
> rule "Validate status for BRONZE"
> when
> Validating ServiceDescription
> Contained in ClientService having
> type equals to "BRONZE"
> then
> # Validate status
> end
>
> In this rule ServiceDescription, ClientService and type literals could be
> anything else (so I don't need to create DSL for each object in domain). But
> this could be easily done through reflection.
>
> Any help with possible approach will be highly appreciated.
>
> Oleg.
>
> ------------------------------
>
> Вы уже с Yahoo!? Испытайте обновленную и улучшенную. Yahoo! Почту<http://ru.mail.yahoo.com>
> !
>
>
> _______________________________________________
> rules-users mailing list
> rules-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-users
>
>
--
Edson Tirelli
Software Engineer - JBoss Rules Core Developer
Office: +55 11 3529-6000
Mobile: +55 11 9287-5646
JBoss, a division of Red Hat @ www.jboss.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-users/attachments/20070712/d426001d/attachment.html
More information about the rules-users
mailing list