Рекурсивный поиск в репозитории 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);

Ресурсы:

Другие вопросы по тегам