I ended up writing my own implementations.
Feel free to improve or add comments for potential improvements.
Additional Information
Java is probably NOT the most efficient way to search through JCR, so be aware of performance (vs using JCR SQL2 ).
However, there are times when using JCR SQL2 will be quite annoying. For example: JCR SQL2 - the order of the query result, as in the JCR browser
I would recommend starting the search as little as possible in the tree.
Decision
Read the comments above each method to find 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); 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; } 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; } }
Using the 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);
Using the 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: