criteria-based updates/deletes (was Re: fix for MeasurementScheduleManagerBean.update)

Joseph Marques jmarques at redhat.com
Tue Nov 2 15:56:28 UTC 2010


On 11/02/2010 10:14 AM, Ian Springer wrote:
>    Yeah, I don't like it either. I was just trying to avoid API changes.
> But since that method is only in the local interface, I guess I can add
> a new method, or methods, with less cryptic semantics, and then
> deprecate, or even just remove, this one.
The root issue here is that we're trying to weave a couple of difference 
use cases into a very concise API:

1) enable the passed metric templates, setting their collection 
intervals to the passed value
2) enable the passed metric templates, keeping collection intervals to 
their existing values
3) disable the passed metric templates (which implies keeping collection 
intervals to their existing values)

Arguably, a user might also want to change the collection intervals 
without affecting the enabled/disabled bit.  If so, both arguments types 
would be optional, which makes using wrapper classes rather natural:

MeasurementScheduleManagerBean {
    updateMeasurementDefinitions(..., Long collectionInterval, Boolean 
enabled) {
       // if collectionInterval not-null, validate it, then include it 
in the update-statement
       // if enabled not-null, include it in the update-statement
    }
}

But that strategy has its own drawbacks:

1) several different permutations of the query need to exist (in this 
case 4 difference versions, because each of the two arguments here can 
be in 2 fundamentally different states [null or not null])
2) a base query must exist, which is then (via string concatenation) 
dynamically augmented/rewritten to account for non-null arguments

-----

I would like us to look into the possibility of using a criteria-based 
solution here, whose mantra from day-1 has been the optionality of 
arguments.  Something like:

MeasurementDefinitionCriteria {
    List<Integer> filterMeasurementDefinitionIds;
    ...
    other existing filters, which help narrow down the list of 
definitions to update
    ...

    // new part of the API
    Long updateCollectionInterval; // if non-null, set the 
collectionInterval
    Boolean updateEnabled; // if non-null, override enabled/disabled bit
}

Here, we've enhanced the criteria API to include new parameter types, 
those with the naming convention "updateXXX".  If any of those are set, 
then the CriteriaQueryGenerator will produce an update-statement 
(instead of a select-statement), whose non-null "updateXXX" values 
generate the list of fields to update on the corresponding entity.

MeasurementScheduleManagerBean {
    int updateMeasurementDefinitionsByCriteria(subject, criteria) {
       // check authorization to ensure caller has permission to update 
monitoring defaults
       CriteriaQueryGenerator generator = new 
CriteriaQueryGenerator(subject, criteria);
       // potentially add authz fragments to the generated query, to 
restrict the update list
       CriteriaQueryRunner<MeasurementDefinition> queryRunner = null;
       queryRunner = new CriteriaQueryRunner(criteria, generator, 
entityManager);
       return queryRunner.executeUpdate();
    }
}

Notice that a new method would be added to the CriteriaQueryRunner 
class, executeUpdate().  When the criteria object is not selecting 
objects (requiring PageList<T> to be returned) the executeUpdate() 
method can be called which will return the count of affected rows instead.

The benefit with this type of solution is that it enables users to 
perform finely-tuned mass updates.  Now, the same Criteria object that 
was able to flexibly find MeasurementDefinition objects (today you can 
search for definitions by id, name, displayName, description, 
resourceTypeName, resourceTypeId, measurementCategory, measurementUnits, 
nmericType, dataType, displayType, enabledDisabled bit, and current 
collectionInterval), and take what it finds and set new values for fields.

So with just a little work at the CriteriaQueryGenerator and 
CriteriaQueryRunner layers, we have a powerful solution that can be used 
to deprecate a wide variety of existing methods across many of our SLSBs.

Note: a criteria-based solution could use the same style to perform 
deletes as well:

SomeManagerBean {
    int deleteSomethingByCriteria(subject, criteria) {
       // check authorization to ensure caller has permission to delete 
something
       CriteriaQueryGenerator generator = new 
CriteriaQueryGenerator(subject, criteria);
       CriteriaQueryRunner<SomeThing> queryRunner = null;
       queryRunner = new CriteriaQueryRunner(criteria, generator, 
entityManager);
       return queryRunner.executeDelete();
    }
}

Again, the benefit is that it exposes the familiar, fine-grained search 
users got from the criteria filters...but now (instead of just returning 
entities across the wire) the criteria framework can update and delete 
stuff too.


More information about the rhq-devel mailing list