This quick start offers examples of the most common use cases for working with filters. For more detail about the concepts and API, see The OGC Filter Model.

Creating or decoding a filter

Creating a filter

You can create filters using the classes in the com.luciad.ogc.filter.model package. For example:

Program: Creating a filter through the API
//The code uses a static import to have easy access to the static methods from that class
//import static com.luciad.ogc.filter.model.TLcdOGCFilterFactory.*;
ILcdOGCCondition condition = eq(property("roadType"), literal("highway"));
TLcdOGCFilter filter = new TLcdOGCFilter(condition);

This results in a TLcdOGCFilter, which is the Java representation of an OGC filter.

Decoding a filter

Often filters are encoded in the XML format. For decoding purposes, you can convert the XML to an TLcdOGCFilter using the TLcdOGCFilterDecoder.

Program: Decoding a filter from an XML file
TLcdOGCFilterDecoder decoder = new TLcdOGCFilterDecoder();
TLcdOGCFilter filter = (TLcdOGCFilter) decoder.decode(filterSourceName);
return filter;

When the filter XML is in a String or an InputStream rather than a file, you can use the static factory methods on TLcdOGCFilterDecoder:

Program: Decoding a filter directly from a String
String filterAsXML = ...;
TLcdOGCFilter filter = TLcdOGCFilterDecoder.decodeFromString(filterAsXML);

If the filter XML is not stored in a file, you can either decode directly from an InputStream or use the static utility method to decode directly from a String. For example

Program: Decoding a filter directly from a InputStream
try(InputStream is = createInputStream()){
  TLcdOGCFilter filter = (TLcdOGCFilter) new TLcdOGCFilterDecoder().decode(is);
}

Evaluating a filter

The TLcdOGCFilter instance contains the definition of the filter only. It cannot be evaluated without extra information. During the evaluation of an OGC filter, the following functionality is needed:

  • An ILcdPropertyRetriever: typical OGC filters compare the value of a property of a domain object with a certain value (for example property(roadType) == "highWay"). The retrieval of the property value from the domain object is delegated to this interface.

  • An ILcdOGCFeatureIDRetriever: if the OGC filter is based on the ID of the objects, the filter delegates the retrieval of the ID to this interface.

  • A default ILcdGeoReference: this reference is used when the filter contains geometries which are defined without a georeference. The filter assumes that such geometries are defined in that default georeference.

By providing this information it is possible to convert the TLcdOGCFilter to an ILcdFilter instance that can be evaluated:

Program: Evaluating a filter
ILcdOGCCondition condition = ...;
TLcdOGCFilter ogcFilter = new TLcdOGCFilter(condition);

TLcdOGCFilterEvaluator evaluator = new TLcdOGCFilterEvaluator();
ILcdFilter filter = evaluator.buildFilter(ogcFilter, new TLcdOGCFilterContext());

Object toEvaluate = ...;
boolean accepted = filter.accept(toEvaluate);

In the code above, default retrievers are used and no custom functions are supported. This works in most cases. If you don’t need to configure the filter evaluator, you can convert an OGC filter directly into an ILcdFilter as follows:

Program: Evaluating a filter without TLcdOGCFilterEvaluator
ILcdOGCCondition condition = ...;
TLcdOGCFilter ogcFilter = new TLcdOGCFilter(condition);
ILcdFilter filter = ogcFilter.asPredicate(new TLcdOGCFilterContext());

Object toEvaluate = ...;
boolean accepted = filter.accept(toEvaluate);

Supporting custom OGC functions

OGC filter expressions can contain a number of pre-defined operations or filter functions: comparison operations spatial operations, and so on. If you have a need for custom operations, you can define your own filter functions in addition to the pre-defined OGC filter operations.

Supporting custom functions through the whole application

If you have custom functions, and you want to support them throughout the application, you can register them globally so that they become available to all TLcdOGCFilterEvaluator instances. This is done by calling the static TLcdOGCFilterEvaluator.registerDefaultFunction method. An example use case for this is a WFS server, where you want to support the custom function for all incoming requests.

Program: Adding support for a custom function for the whole application
//At the start of the application
TLcdXMLName customFunctionName = ...;
ILcdEvaluatorFunction customFunction = ...;
TLcdOGCFilterEvaluator.registerDefaultFunction(customFunctionName, customFunction);

//...
//Later on in the application
ILcdOGCCondition condition = ...;
TLcdOGCFilter ogcFilter = new TLcdOGCFilter(condition);

//This evaluator will support the custom function registered at the start of the application
TLcdOGCFilterEvaluator evaluator = new TLcdOGCFilterEvaluator();
ILcdFilter filter = evaluator.buildFilter(ogcFilter, new TLcdOGCFilterContext());

Object toEvaluate = ...;
boolean accepted = filter.accept(toEvaluate);

Program: Registering a custom function shows an example implementation of a custom ILcdEvaluatorFunction.

Supporting custom functions in a single evaluator

You can add support for custom functions by registering them on the evaluator instance using the TLcdOGCFilterEvaluator.registerFunction method. Note that the custom function will only be supported in that specific evaluator.

Program: Adding support for a custom function in a single evaluator
ILcdOGCCondition condition = ...;
TLcdOGCFilter ogcFilter = new TLcdOGCFilter(condition);

TLcdOGCFilterEvaluator evaluator = new TLcdOGCFilterEvaluator();
//register the custom function on the evaluator
TLcdXMLName customFunctionName = ...;
ILcdEvaluatorFunction customFunction = ...;
evaluator.registerFunction(customFunctionName, customFunction);

//The evaluation of the filter is identical as without custom functions
ILcdFilter filter = evaluator.buildFilter(ogcFilter, new TLcdOGCFilterContext());

Object toEvaluate = ...;
boolean accepted = filter.accept(toEvaluate);

Program: Registering a custom function shows an example implementation of a custom ILcdEvaluatorFunction.

Example of a custom function

Program: Registering a custom function shows an example of a custom function implementation, in which a string is converted to upper case.

Program: Registering a custom function (from samples/ogc/filter/xml/MainPanel)
ILcdEvaluatorFunction toUpperCaseFunction = new ILcdEvaluatorFunction() {
  @Override
  public Object apply(Object[] aArguments,
                      Object aCurrentObject,
                      TLcdOGCFilterContext aOGCFilterContext) {
    return aArguments.length == 1 && aArguments[0] != null ?
           aArguments[0].toString().toUpperCase() : null;
  }

  @Override
  public int getArgumentCount() {
    return 1;
  }
};

Encoding a filter

TLcdOGCFilter instances can be converted back to their XML representation using the TLcdOGCFilterEncoder. For example:

Program: Encoding an OGC filter to a file
TLcdOGCFilter filter = ...;
TLcdOGCFilterEncoder encoder = new TLcdOGCFilterEncoder();
String outputFile = "path/to/file.xml";
encoder.encode(filter, outputFile);

The TLcdOGCFilterEncoder class also allows to store the XML representation of the TLcdOGCFilter into a String or an OutputStream:

Program: Storing the XML representation of a TLcdOGCFilter into an OutputStream
TLcdOGCFilter filter = ...;
try(Outputstream os = ...){
  new TLcdOGCFilterEncoder().encode(filter, os);
}
Program: Storing the XML representation of a TLcdOGCFilter into a String
TLcdOGCFilter filter = ...;
String xmlEncodedFilter = TLcdOGCFilterEncoder.encodeToString(filter);