Reviews
Oracle CoherenceOracle Coherence: Simplifying Coherence Queries
As you have probably realized by now, Coherence queries can become quite cumbersome to create as the number of attributes used within the query grows, especially if non-default value extractors need to be used.
One, and possibly the best, approach would be to implement a real query language. We could define a grammar for Coherence queries that would be used to parse a SQL-like query string into a parse tree representing a Coherence filter. This would actually be fairly straightforward, as grammar elements would map pretty much directly to the built-in filters provided by Coherence.
However, this would distract us from the main topic of the book and lead us into the discussion of topics such as language grammars and parsers, so implementation of a full-blown Coherence query language is out of the scope of this book.
What we will do instead is implement a FilterBuilder class that will allow us to define the queries in a simpler way. While this approach won't allow us to express all possible queries, it will cover a large number of the most common use cases.
Filter builder
The idea behind the FilterBuilder implementation is that many queries are based on simple attribute comparisons, where multiple attribute comparisons are concatenated using the logical AND, or less often OR operator.
If you review the table of the built-in filter types at the beginning of this chapter, you will see that Coherence already provides all the core facilities we need to implement this: we have all the common comparison operators, as well as some of the less common ones, and there are AllFilter and AnyFilter, which allow us to create logical AND and OR filters for an array of filters respectively. What we don't have is an easy way to create an array of filters, and that's exactly what the FilterBuilder will help us do.
The goal is to be able to create a filter using code similar to this:
- Filter filter = new FilterBuilder()
- .equals("id.accountId", 123)
- .between("time", from, to)
- .build()
This will allow us to define complex queries in a much shorter and significantly more readable way. In order to support the previous syntax, we can implement the FilterBuilder class as follows:
- public class FilterBuilder {
- private Class defaultExtractorType
- private List<filter></filter> filters = new ArrayList<filter></filter>()
- // constructors
- public FilterBuilder() {
- this(PropertyExtractor.class)
- }
- public FilterBuilder(Class defaultExtractorType) {
- this.defaultExtractorType = defaultExtractorType
- }
- // public members
- public FilterBuilder equals(String propertyName,
- Object value) {
- return equals(createExtractor(propertyName), value)
- }
- public FilterBuilder equals(ValueExtractor extractor,
- Object value) {
- filters.add(new EqualsFilter(extractor, value))
- return this
- }
- public FilterBuilder notEquals(String propertyName,
- Object value) {
- return notEquals(createExtractor(propertyName), value)
- }
- public FilterBuilder notEquals(ValueExtractor extractor,
- Object value) {
- filters.add(new NotEqualsFilter(extractor, value))
- return this
- }
- public FilterBuilder greater(String propertyName,
- Comparable value) {
- return greater(createExtractor(propertyName), value)
- }
- public FilterBuilder greater(ValueExtractor extractor,
- Comparable value) {
- filters.add(new GreaterFilter(extractor, value))
- return this
- }
- // and so on...
- }
Basically, we are implementing two overloaded methods for each built-in filter: one that accepts a value extractor as the first argument, and one that accepts a string and creates a value extractor for it.
However, unlike the built-in filters, we do not create an instance of a ReflectionExtractor automatically, but delegate the actual creation of an extractor to the createExtractor factory method:
- protected ValueExtractor createExtractor(String propertyName) {
- if (propertyName.indexOf('.') >= 0) {
- return new ChainedExtractor(
- createExtractorArray(propertyName.split(".")))
- }
- if (propertyName.indexOf(',') >= 0) {
- return new MultiExtractor(
- createExtractorArray(propertyName.split(",")))
- }
- return createDefaultExtractor(propertyName)
- }
As you can see, if the specified property name is a dot-separated string, we will create an instance of a ChainedExtractor. Similarly, we will create an instance of a MultiExtractor for a comma-separated list of property names.
For all other properties, we will delegate extractor creation to the createDefaultExtractor method:
- protected ValueExtractor createDefaultExtractor(String propertyName) {
- Constructor ctor = getConstructor(defaultExtractorType)
- return (ValueExtractor) ctor.newInstance(propertyName)
- }
This allows us to control on a case-by-case basis which value extractor should be used within our filter. In most cases, the default PropertyExtractor should work just fine, but you can easily change the behavior by specifying a different extractor class as a constructor argument:
- Filter filter = new FilterBuilder(ReflectionExtractor.class)
- .equals("getCustomerId", 123)
- .greater("getTotal", 1000.0)
- .build()
You can even specify your own custom extractor class--the only requirement is that it implements a constructor that accepts a single string argument.
Oracle Coherence
- Oracle Coherence 3.5
- Oracle Coherence: Distributed Caching
- Oracle Coherence: In-place and Parallel Processing
- Oracle Coherence: Coherence within the Oracle Ecosystem
- Oracle Coherence: Querying The Data Grid
- Oracle Coherence: Built-in Filters
- Oracle Coherence: Value and Reflection Extractor
- Oracle Coherence: Other built-in value extractors
- Oracle Coherence: Implementing Custom Value Extractor
- Oracle Coherence: Simplifying Coherence Queries
- Oracle Coherence: Obtaining Query Results
- Oracle Coherence: Controlling Query Scope Using Data Affinity
- Oracle Coherence: Querying Near Cache
- Oracle Coherence: Paging Over Query Results
- Oracle Coherence: Anatomy of an Index
- Oracle Coherence: Creating Indexes
- Oracle Coherence: Query Limitations
- Oracle Coherence: Aggregators
- Oracle Coherence: Built-in Aggregators
- Oracle Coherence: Implementing LookupValuesAggregator







