Рекурсивный поиск в репозитории JCR через Java
Я знаю, как искать что-то в JCR через запросы JCR SQL2.
Тем не менее, я хотел бы использовать Java в некоторых случаях, используя JCR API: javax.jcr.Node
, javax.jcr.NodeIterator
и тому подобное.
Боюсь, я просто заново изобрету колесо, кодируя свое.
Есть ли что-нибудь уже доступно (Gist
, Github
или же else
)?
3 ответа
Вы можете использовать ItemVisitor для рекурсивного обхода хранилища, собирая все элементы, которые соответствуют вашим критериям.
Например, распечатать все свойства типа Long
:
Node root = session.getRootNode();
root.accept(new ItemVisitor() {
@Override
public void visit(Property property) throws RepositoryException {
if (!property.isMultiple() && property.getType() == PropertyType.LONG) {
System.out.println(property.getName() + " = " + property.getLong());
}
}
@Override
public void visit(Node node1) throws RepositoryException {
NodeIterator children = node1.getNodes();
while (children.hasNext()) {
visit(children.nextNode());
}
}
});
Вы можете использовать для этого SlingQuery. Он вдохновлен jQuery и соответствует синтаксису. Вы должны использовать его только для поиска небольшого количества узлов (в лучшем случае до 100), потому что запросы обхода идут медленно.
редактировать
Ваш пример может быть преобразован в следующий SlingQueries (не тестировался):
SlingQuery.$(startResource).find("[name=teasers][title=awesome-teaser]")
SlingQuery.$(startResource).find("[name][controlName]")
С тех пор SlingQuery является частью Apache Sling, поэтому хранилище github кажется заброшенным.
Примечание. Вы можете статически импортировать знак доллара и отбросить статический доступ через SlingQuery в вашем синтаксисе, таком как $(resource).find("...");
Я закончил писать свои собственные реализации.
Не стесняйтесь улучшать или добавлять комментарии для потенциальных улучшений.
Дальнейшая информация
Java, вероятно, НЕ самый эффективный способ поиска по JCR, так что помните о производительности (против использования JCR SQL2
).
Однако есть случаи, когда использование JCR SQL2 будет довольно раздражающим. Например: JCR SQL2 - порядок запроса результатов, как в браузере JCR
Я бы рекомендовал начать поиск как можно ниже в дереве.
Решение
Прочитайте комментарии выше каждого метода, чтобы найти больше.
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;
}
}
Использование первого служебного метода
/*
* 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);
Использование второго вспомогательного метода
/*
* 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);