PredicateConverter.java 12.2 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  org.apache.jackrabbit.commons.query.GQL
 *  org.apache.jackrabbit.commons.query.GQL$ParserCallback
 *  org.apache.jackrabbit.util.Text
 */
package com.day.cq.search;

import com.day.cq.search.Predicate;
import com.day.cq.search.PredicateGroup;
import com.day.cq.search.impl.builder.PredicateWalker;
import org.apache.jackrabbit.commons.query.GQL;
import org.apache.jackrabbit.util.Text;

import javax.jcr.RepositoryException;
import javax.jcr.Session;
import java.util.Comparator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public abstract class PredicateConverter {
    public static final String GROUP_PARAMETER_PREFIX = "p";
    public static final String IGNORE_PARAMETER_PREFIX = "_";
    private static final String RANGE_DELIMITER = "..";
    private static final String ORDER = "order";
    private static final String DATERANGE_PRED = "daterange";
    private static final String RANGEPROP_PRED = "rangeproperty";
    private static final String DATE_REGEX = ".*[0-9]+-.*";
    private static final String RANGE_REGEX = "(.*)\\.{2,}(.*)";

    public static PredicateGroup createPredicates(Map predicateParameterMap) {
        PredicateGroup root = new PredicateGroup();
        PredicateTreeNode rootNode = new PredicateTreeNode(root);
        for (Object nameObj : predicateParameterMap.keySet()) {
            String[] valueArray;
            String name = (String)nameObj;
            if (name != null && name.startsWith("_")) continue;
            Object valueObj = predicateParameterMap.get(name);
            String value = valueObj instanceof String ? (String)valueObj : (valueObj instanceof String[] ? ((valueArray = (String[])valueObj).length == 0 ? null : valueArray[0]) : null);
            if (PredicateConverter.isGroupParameter(name)) {
                root.set(PredicateConverter.getGroupParameterName(name), value);
                continue;
            }
            rootNode.insert(name, value);
        }
        rootNode.generatePredicateTree();
        return root;
    }

    public static Map<String, String> createMap(PredicateGroup root) {
        CollectParameters collector = new CollectParameters();
        collector.visit(root);
        return collector.getParameters();
    }

    public static String toURL(PredicateGroup group) {
        StringBuffer urlPart = new StringBuffer();
        Map<String, String> params = PredicateConverter.createMap(group);
        for (String key : params.keySet()) {
            if (urlPart.length() > 0) {
                urlPart.append("&");
            }
            urlPart.append(Text.escape((String)key)).append("=");
            String value = params.get(key);
            if (value == null) continue;
            urlPart.append(Text.escape((String)value));
        }
        return urlPart.toString();
    }

    private static boolean isGroupParameter(String subParameter) {
        return subParameter.startsWith("p.");
    }

    private static String getGroupParameterName(String subParameter) {
        return subParameter.substring("p.".length());
    }

    public static PredicateGroup createPredicatesFromGQL(String statement) throws RepositoryException {
        final PredicateGroup parentGroup = new PredicateGroup();
        final PredicateGroup conjointGroup = new PredicateGroup();
        GQL.ParserCallback callback = new GQL.ParserCallback(){

            public void term(String property, String value, boolean optional) throws RepositoryException {
                PredicateConverter.pushExpression(property, value, optional, parentGroup, conjointGroup);
            }
        };
        statement = statement.replaceAll(" *: *", ":").replaceAll(" *- *", "-");
        GQL.parse((String)statement, (Session)null, (GQL.ParserCallback)callback);
        parentGroup.addAll(conjointGroup);
        return parentGroup;
    }

    private static void pushExpression(String property, String value, boolean optional, PredicateGroup parentGroup, PredicateGroup conjointGroup) {
        if (property.equals("path") || property.equals("order") || property.equals("type") || property.equals("limit") || property.equals("offset") || property.equals("guessTotal") || property.equals("excerpt")) {
            if (property.equals("order")) {
                Predicate orderPredicate = new Predicate("orderby");
                if (value.startsWith("-")) {
                    orderPredicate.set("orderby", value.length() > 1 ? "@" + value.substring(1) : "");
                    orderPredicate.set("sort", "desc");
                } else if (value.startsWith("+")) {
                    orderPredicate.set("orderby", value.length() > 1 ? "@" + value.substring(1) : "");
                    orderPredicate.set("sort", "asc");
                } else {
                    orderPredicate.set("orderby", "@" + value);
                }
                parentGroup.add(orderPredicate);
            } else if (property.equals("path") || property.equals("type")) {
                conjointGroup.add(new Predicate(property).set(property, value));
            } else {
                parentGroup.set("limit", value);
            }
        } else {
            Predicate predicate;
            if (property.length() > 0) {
                if (value.contains("..")) {
                    String lower = "";
                    String upper = "";
                    Pattern p = Pattern.compile("(.*)\\.{2,}(.*)");
                    Matcher m = p.matcher(value);
                    if (m.find()) {
                        lower = m.group(1).trim();
                        upper = m.group(2).trim();
                    }
                    String predName = lower.matches(".*[0-9]+-.*") || upper.matches(".*[0-9]+-.*") ? "daterange" : "rangeproperty";
                    if ("rangeproperty".equals(predName)) {
                        predicate = new Predicate("rangeproperty");
                        if (lower.length() == 0) {
                            lower = Long.toString(-9223372036854775807L);
                        }
                        if (upper.length() == 0) {
                            upper = Long.toString(9223372036854775806L);
                        }
                    } else {
                        predicate = new Predicate("daterange");
                    }
                    predicate.set("property", property);
                    predicate.set("lowerBound", lower);
                    predicate.set("upperBound", upper);
                } else {
                    predicate = new Predicate("property");
                    predicate.set("property", property);
                    predicate.set("value", value);
                }
            } else {
                predicate = new Predicate("fulltext");
                predicate.set("fulltext", value);
            }
            if (optional && parentGroup.size() > 0) {
                Predicate lastElement = parentGroup.get(parentGroup.size() - 1);
                if (lastElement instanceof PredicateGroup && !((PredicateGroup)lastElement).allRequired()) {
                    ((PredicateGroup)lastElement).add(predicate);
                    parentGroup.set(parentGroup.size() - 1, (PredicateGroup)lastElement);
                } else {
                    PredicateGroup optionalGrp = new PredicateGroup();
                    optionalGrp.setAllRequired(false);
                    optionalGrp.add(lastElement);
                    optionalGrp.add(predicate);
                    parentGroup.set(parentGroup.size() - 1, optionalGrp);
                }
            } else {
                parentGroup.add(predicate);
            }
        }
    }

    private static class LongOrStringComparator
    implements Comparator<Object> {
        public static final LongOrStringComparator INSTANCE = new LongOrStringComparator();

        private LongOrStringComparator() {
        }

        @Override
        public int compare(Object o1, Object o2) {
            if (o1 instanceof Long && o2 instanceof Long) {
                return ((Long)o1).compareTo((Long)o2);
            }
            if (o1 instanceof String && o2 instanceof String) {
                return ((String)o1).compareTo((String)o2);
            }
            if (o1 instanceof Long) {
                return 1;
            }
            if (o2 instanceof Long) {
                return -1;
            }
            return -1;
        }
    }

    private static class PredicateTreeNode {
        public Predicate predicate;
        private SortedMap<Object, PredicateTreeNode> kids = new TreeMap<Object, PredicateTreeNode>(LongOrStringComparator.INSTANCE);

        public PredicateTreeNode(Predicate p) {
            this.predicate = p;
        }

        public void insert(String name, String value) {
            String[] split = name.split("\\.", 2);
            String predicateName = split[0];
            String subParameter = split.length > 1 ? split[1] : null;
            Object key = predicateName;
            String predicateType = predicateName;
            if (predicateName.contains("_")) {
                split = predicateName.split("_", 2);
                try {
                    long index = Long.parseLong(split[0]);
                    key = index;
                    predicateType = split.length > 1 ? split[1] : null;
                }
                catch (NumberFormatException e) {
                    // empty catch block
                }
            }
            if (predicateType == null) {
                return;
            }
            PredicateTreeNode node = null;
            if (this.kids.containsKey(key)) {
                node = this.kids.get(key);
            } else {
                Predicate p = "group".equals(predicateType) ? new PredicateGroup(predicateName) : new Predicate(predicateName, predicateType);
                node = new PredicateTreeNode(p);
                this.kids.put(key, node);
            }
            if (subParameter == null) {
                subParameter = predicateType;
            }
            if (node != null && subParameter != null) {
                if (node.predicate instanceof PredicateGroup) {
                    if (PredicateConverter.isGroupParameter(subParameter)) {
                        node.predicate.set(PredicateConverter.getGroupParameterName(subParameter), value);
                    } else {
                        node.insert(subParameter, value);
                    }
                } else {
                    node.predicate.set(subParameter, value);
                }
            }
        }

        public void generatePredicateTree() {
            if (this.predicate instanceof PredicateGroup) {
                PredicateGroup group = (PredicateGroup)this.predicate;
                for (PredicateTreeNode node : this.kids.values()) {
                    node.generatePredicateTree();
                    group.add(node.predicate);
                }
            }
        }
    }

    private static class CollectParameters
    extends PredicateWalker {
        private Map<String, String> result = new TreeMap<String, String>();

        private CollectParameters() {
        }

        @Override
        protected void visitInternal(Predicate predicate) {
            if (predicate instanceof PredicateGroup) {
                PredicateGroup group = (PredicateGroup)predicate;
                Map<String, String> groupParams = group.getParameters();
                String path = group.getPath();
                path = path == null ? "" : path + ".";
                for (String key : groupParams.keySet()) {
                    this.result.put(path + "p" + "." + key, groupParams.get(key));
                }
            } else {
                Map<String, String> params = predicate.getParameters();
                String path = predicate.getPath();
                for (String key : params.keySet()) {
                    if (key.equals(predicate.getType())) {
                        this.result.put(path, params.get(key));
                        continue;
                    }
                    this.result.put(path + "." + key, params.get(key));
                }
            }
        }

        public Map<String, String> getParameters() {
            return this.result;
        }
    }

}