Darius,

I created the EvaluableRule abstract class because of the following reasons:

1. I'm using the "parameters" parameter of the eval method to pass
around data that I want to include in the rule evaluation. And example
of the data would be concept name and encounter type name. I
introduced a new method to validate these parameters, and also I
introduced a new method to enable the rule to specify what kind of
parameters are needed in the rule evaluation process.

// this class hold the definition of a parameter
EvaluableParameter {
    String name;
    Class parameterClass;
    Boolean required;
    Object defaultValue;
}

EvaluableRule {
    // validate the parameters passed to the eval method in the rule
to make sure it's a perfect match with the definition
    protected void validateParameters(final Map<String, Object>
parameters) throws LogicException {
    }
    // method will return a set of applicable parameters for the rule
    protected Set<EvaluableParameter> getEvaluationParameters() {
    }
}

2. I used the asm library to perform rule auto-registering. Basically,
there's a mechanism in the module to iterate the rule package
(org.openmrs.module.clinicalsummary.rule), read every *Rule class in
there recursively and then read the class to get the declared token
name and register them. This way, I just need to write my own rule in
the correct package and when I deploy the module the rule will
automagically get registered. I introduced a new method to force every
class to say what the token name is for the rule:

EvaluableRule {
    protected abstract String getEvaluableToken();
}

3. Rule dependency checking (This is not implemented but maybe we should).
Currently we have:
public String[] getDependencies()

I think we should use this to perform checking on the tokens that a
rule might need to perform execution correctly. For example
ExampleRule says they are depend on token "Another Rule" and "Some
Other Rule", we need to have a mechanism to ensure that those token
are registered and the class are actually exists.

4. Our grammar translation isn't clear at all. We tried to sit down
and come up with a better grammar definition, but never finished it.
:)
It's easy enough to create a simple criteria -- for example, to get
CD4 records, we just need to create LogicCriteria with CD4 as the root
expression. But things will get hairy when we want to get obs with
coded value. For example, we want to get obs with concept "TESTS
ORDERED" and value coded "CD4 PANEL" :)

So, for the module I created 4 basic rules to get Encounter and Obs
data from the database. The encounters rule can accept encounter type
names and location names and then pass this to service call to get the
encounter data. I didn't call the OpenMRS API because I need to pass
lots of null values to the API which I don't really like. :)

So I have service method that will call the following hibernate call:
// the following restrictions map comes from the rule parameters. the
key is the encounter property, and the collection is the possible
values
public List<Encounter> getPatientEncounters(final Integer patientId,
final Map<String, Collection<OpenmrsObject>> restrictions) {
    // create a hibernate criteria on the encounter object
    Criteria criteria =
sessionFactory.getCurrentSession().createCriteria(Encounter.class);
    // restrict the encounter that will be returned to specific patient only
    criteria.add(Restrictions.eq("patientId", patientId));

    // create a dummy encounter object
    Encounter encounter = new Encounter();
    // iterate over each property in the restriction map
    for (String property : restrictions.keySet()) {
        // get the actual object that will restrict the encounter.
this will contains the list of encounter type or list of location
        // or list of provider (currently not being used) passed from caller
        Collection<OpenmrsObject> propertyValues = restrictions.get(property);
        // check to make sure the list is not empty and the property
is readable. example of the property for encounter are
        // encounterType or location of the encounter
        if (CollectionUtils.isNotEmpty(propertyValues) &&
PropertyUtils.isReadable(encounter, property)) {
            // create a restriction on the property with the above
list as the value
            criteria.add(Restrictions.in(property, propertyValues));
            // add ordering on that property to prevent slowness when
ordering only on encounter datetime (1.6.x only)
            criteria.addOrder(Order.asc(property));
        }
    }

    // exclude all voided encounters
    criteria.add(Restrictions.eq("voided", Boolean.FALSE));
    criteria.addOrder(Order.desc("encounterDatetime"));
    // continued ...
}

5. The caching mechanism of the rule only happens on the outer rule.
This means that when a rule is calling another rule inside a rule, the
intermediary result of the inner rule is not cached.
public class ExampleRule {
    // If this is the outer rule and this is called through
LogicService's eval, then it will be cached in the context
    public Result eval (final LogicContext context, final Integer
patientId, final Map<String, Object> parameters) throws LogicException
{
        AnotherRule anotherRule = new AnotherRule();
        // The following result will not get cached
        Result anotherResult = anotherRule.eval(context, patientId, parameters);
    }
}

On Thu, Sep 15, 2011 at 8:51 PM, Darius Jazayeri <[email protected]> wrote:
> Hi Win,
> I noticed on today's dev call that you've implemented an abstract
> "EvaluableRule" class that I assume all your rules are extending. I was
> hoping you could describe what about the regular Rule interface, Groovy rule
> definitions, etc, were insufficient, that led to adding this.
> -Darius
> ________________________________
> Click here to unsubscribe from OpenMRS Developers' mailing list



-- 
Thanks,

Nyoman Ribeka

_________________________________________

To unsubscribe from OpenMRS Developers' mailing list, send an e-mail to 
[email protected] with "SIGNOFF openmrs-devel-l" in the  body (not 
the subject) of your e-mail.

[mailto:[email protected]?body=SIGNOFF%20openmrs-devel-l]

Reply via email to