I ended up writing my own implementations.
Feel free to improve or add comments for potential improvements.
Further info
Java is probably NOT the most efficient way of searching through the JCR, so mind the performance hit (vs using JCR SQL2
).
However, there are cases where using JCR SQL2 will be rather annoying. For instance: JCR SQL2 - result query order as in JCR browser
I'd recommend launching your search as low as possible in the tree.
Solution
Read the comments above each method to find our more.
package com.nameoforganization.jcr;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JcrSearchUtils {
private static final Logger log = LoggerFactory.getLogger(JcrUtil.class);
/*
* Recursive search in JCR tree: properties matching values
* Parameters:
* - node: node to start the search from
* - propertyValueConditions: properties searched along with the value expected for it
* - searchResults: set this to null when launching the search
*/
public static ArrayList<Node> searchRecursivelyPropMatchVal(Node node, HashMap<String, String> propertyValueConditions, ArrayList<Node> searchResults) {
if(searchResults == null){
searchResults = new ArrayList<Node>();
}
try{
NodeIterator list = node.getNodes();
while(list.hasNext()) {
Node currentSubNode = list.nextNode();
Boolean hasAllRequiredPropsAndVals = true;
for (Map.Entry<String, String> entry : propertyValueConditions.entrySet()) {
String propertyName = entry.getKey();
Object searchedValue = entry.getValue();
if ( !currentSubNode.hasProperty(propertyName) || !currentSubNode.getProperty(propertyName).getString().equals(searchedValue) ){
hasAllRequiredPropsAndVals = false;
}
}
if ( hasAllRequiredPropsAndVals ){
searchResults.add(currentSubNode);
}
searchRecursivelyPropMatchVal(currentSubNode, propertyValueConditions, searchResults);
}
return searchResults;
} catch (RepositoryException rpe){
log.info("Recursive search in JCR tree (properties matching values) via JCR API failed");
}
return null;
}
/*
* Recursive search in JCR tree: required properties present
* Parameters:
* - node: node to start the search from
* - propertyValueConditions: properties searched along with the value expected for it
* - searchResults: set this to null when launching the search
*/
public static ArrayList<Node> searchRecursivelyPropPres(Node node, ArrayList<String> propertyPresConditions, ArrayList<Node> searchResults) {
if(searchResults == null){
searchResults = new ArrayList<Node>();
}
try{
NodeIterator list = node.getNodes();
while(list.hasNext()) {
Node currentSubNode = list.nextNode();
Boolean hasAllRequiredProperties = true;
for (String propertyName : propertyPresConditions) {
if ( !currentSubNode.hasProperty(propertyName) ){
hasAllRequiredProperties = false;
}
}
if( hasAllRequiredProperties ){
searchResults.add(currentSubNode);
}
searchRecursivelyPropPres(currentSubNode, propertyPresConditions, searchResults);
}
return searchResults;
} catch (RepositoryException rpe){
log.info("Recursive search in JCR tree (required properties present) via JCR API failed");
}
return null;
}
}
Usage of first utility method
/*
* Search nodes with properties:
* "name" having value "teasers"
* "title" having value "awesome-teaser"
*/
// Node startingNode = set this yourself :)
HashMap<String, String> propertyValueConditions = new HashMap<String, String>();
propertyValueConditions.put("name", "teasers");
propertyValueConditions.put("title", "awesome-teaser");
ArrayList<Node> nodesFound = JcrUtil.searchRecursivelyPropMatchVal(startingNode, propertyValueConditions, null);
Usage of second utility method
/*
* Search nodes having properties "name" and "controlName"
*/
// Node startingNode = set this yourself :)
ArrayList<String> propertyPresConditions = new ArrayList<String>();
propertyPresConditions.add("name");
propertyPresConditions.add("controlName");
ArrayList<Node> nodesFound = JcrUtil.searchRecursivelyPropPres(startingNode, propertyPresConditions, null);
Resources: