Apache Sling Resource Filter

Clone this repo:
  1. 4efb3d2 Updating badges for org-apache-sling-resource-filter by Radu Cotescu · 10 months ago master
  2. c809a94 SLING-7245 - Validate pull requests using Jenkins by Robert Munteanu · 11 months ago
  3. 30e9f84 trivial: added license header to *.md files by Radu Cotescu · 1 year, 3 months ago
  4. eb88769 SLING-7215 - [nice-to-have] Add a CONTRIBUTING file to every module by Radu Cotescu · 1 year, 3 months ago
  5. 7189242 SLING-7216 - [nice-to-have] Add a CODE_OF_CONDUCT file to every module by Radu Cotescu · 1 year, 3 months ago

Build Status Test Status Maven Central JavaDocs License

Resource Predicate Service

ResourcePredicate is a service that allows you to convert a string that defines a simple matching requirements into a Predicate<Resource> for use with the Collections and the Streams Java API. In addition it also allows you to add parameters to the underlying context that the script will use.

@Reference
ResourcePredicates rp;

Predicate<Resource> predicate = rp.parse("[jcr:content/created] < 2013-08-08T16:32");
resourceCollection.stream().filter(predicate).forEach(
    resource -> System.out.println(resource.getPath())
);

Resource Stream

ResourceStream is a general utility to provide a Stream<Resource> which traverses a resource and it's subtree. The implementation takes a Predicate<Resource> object as part of the stream creation to define a branch selector that controls which children of a resource are followed.

In addition there is a getChildren(Predicate) method which returns a filtered list of children of the given resource.

Resource Filter Stream

ResourceFilterStream combines the ResourceStream functionality with the ResourcePredicates service to provide an ability to define a Stream<Resource> that follows specific child pages and looks for specific Resources as defined by the resources filter script. The ResourceStreamFilter is access by adaption.

     ResourceFilterStream rfs = resource.adaptTo(ResourceFilterStream.class);
     
     rfs
        .setBranchSelector("[jcr:primaryType] == 'cq:Page'")
        .setChildSelector("[jcr:content/sling:resourceType] != 'apps/components/page/folder'")
        .stream()
        .collect(Collections.toList());

ResourceFilter Scripting

Operators

NameComparison TypeDescription
andNALogical AND
&&NALogical AND
orNALogical OR
||NALogical OR
==StringEqual operator for Strings
<NumberLess than operator for Numbers
<=NumberLess than or equal operator for Numbers
>NumberGreater than operator for Numbers
>=NumberGreater than or equal operator for Numbers
!=StringIs not equal to for Strings
~=String - RegexRegex match against String
less thanNumberless than operator for Numbers
greater thanNumbergreater than operator for Numbers
isStringEqual operator for Strings
is notStringIs not equal operator for Strings
likeString - RegexRegex match against String
is likeString - RegexRegex match against String
not likeString - RegexRegex does not match String
containsString[]String[] contains all of items
contains notString[]String[] does not contain all of the items
contains anyString[]String[] contains at least one of items
contains not anyString[]String[] does not contain any of the items

Logical Operators

The ‘and’ and ‘or’ operators are logical operators that string together conditions. ‘And’ operators take precedence. ‘Or’ operators evaluate from left to right

Values

Values for comparison are obtained through multiple methods

MethodDescription
LiteralSingle(') or double (") quoted text in the query will be interpreted as a String. Boolean values of true and false will be translated to a String.
PropertyA String between square brackets ‘[’,']'s will be interpreted as a property value and will be retrieved from the Resource using the get method
FunctionA string followed by parens containing an optional comma separated list of values.

Types

All types are converted to either a String or a Number. For direct equivalence the comparison is done as a String. For relational comparisons the object will be adapted to a number.

Dates/Instants

Dates are special, there are multiple ways to enter a date.

In line, as part of the query, a date can be identified as a string that conforms to a standard ISO-8601 date time.

‘2013-08-08T16:32:59.000’

‘2013-08-08T16:32:59’

‘2013-08-08T16:32’

Are all valid date representations that are defaulting to the UTC timezone.

For a ISO8601 date with timezone offset use the date function.

date(‘2013-08-08T16:32:59.000+02:00’)

If you need a different date format then the date function can accommodate that

date(‘2013-08-08’,‘yyyy-MM-dd’)

Or you can add your own custom Function

Dates are transitionally represented as a java.util.Instant which is then converted to a String in ISO-8601 format or as a Long number based on the type of comparison. The number representing the time in milliseconds since the EPOCH UTC region

Functions

Functions provide the ability to add additional functionality to the Filter language. A Function is written in the format

string ‘(’ comma, separated, list() ‘)’

All functions MUST return either a String, a Number, or an Instant. Strings are assumed to be using the default UTF encoding.

OOTB Functions are:

NameArgumentsReturnsDescription
namenoneStringProvides the name of the resource
date0 - 2InstantFirst argument is string representation of the date, second argument is a standard Java DateFormat representation of the value. No argument returns the current time.
pathnoneStringpath of the tested resource

Parameters

The ResourceFilter and ResourceFilteStream can have key value pairs added so that the values may be used as part of the script resolution. Parameters are accessed by using the dollar sign ‘$’

rfs.setBranchSelector("[jcr:content/sling:resourceType] != $type").addParam("type","apps/components/page/folder");

Optimizing Traversals

Similar to indexing in a query there are strategies that you can do within a tree traversal so that traversals can be done in an efficient manner across a large number of resources. The following strategies will assist in traversal optimization.

Limit traversal paths

In a naive implementation of a tree traversal the traversal occurs across all nodes in the tree regardless of the ability of the tree structure to support the nodes that are being looked for. An example of this is a tree of Page resources that have have a child node of jcr:content which contains a subtree of data to define the page structure. If the jcr:content node is not capable of having a child resource of type Page and the goal of the traversal is to identify Page resources that match a specific criteria then the traversal of the jcr:content node can not lead to additional matches. Using this knowledge of the resource structure, you can improve performance by adding a branch selector that prevents the traversal from proceeding down a non productive path

Limit memory consumption

The instantiation of a Resource object from the underlying ResourceResolver is a non trivial consumption of memory. When the focus of a tree traversal is obtaining information from thousands of Resources, an effective method is to extract the information as part of the stream processing or utilizing the forEach method of the ResourceStream object which allows the resource to be garbage collected in an efficient manner.