| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.jackrabbit.oak.plugins.index.aggregate; |
| |
| import static com.google.common.collect.Lists.newArrayList; |
| import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE; |
| import static org.apache.jackrabbit.oak.api.Type.STRING; |
| import static org.apache.jackrabbit.oak.commons.PathUtils.elements; |
| import static org.apache.jackrabbit.oak.commons.PathUtils.getDepth; |
| import static org.apache.jackrabbit.oak.commons.PathUtils.getName; |
| import static org.apache.jackrabbit.oak.commons.PathUtils.getParentPath; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.apache.jackrabbit.oak.api.PropertyState; |
| import org.apache.jackrabbit.oak.spi.query.QueryIndex; |
| import org.apache.jackrabbit.oak.spi.state.NodeState; |
| |
| /** |
| * List based NodeAggregator |
| * |
| */ |
| public class SimpleNodeAggregator implements QueryIndex.NodeAggregator { |
| |
| public static final String INCLUDE_ALL = "*"; |
| |
| private final List<ChildNameRule> aggregates = new ArrayList<ChildNameRule>(); |
| |
| @Override |
| public Iterator<String> getParents(NodeState root, String path) { |
| return getParents(root, path, true); |
| } |
| |
| private Iterator<String> getParents(NodeState root, String path, |
| boolean acceptStarIncludes) { |
| |
| int levelsUp = 0; |
| Set<String> primaryType = new HashSet<String>(); |
| for (ChildNameRule r : aggregates) { |
| String name = getName(path); |
| for (String inc : r.includes) { |
| // check node name match |
| if (name.equals(getName(inc))) { |
| levelsUp = getDepth(inc); |
| primaryType.add(r.primaryType); |
| if (acceptStarIncludes) { |
| break; |
| } |
| } |
| if (acceptStarIncludes) { |
| // check '*' rule, which could span over more than one level |
| if (INCLUDE_ALL.equals(getName(inc))) { |
| // basic approach to dealing with a '*' include |
| levelsUp = Math.max(getDepth(inc), levelsUp); |
| primaryType.add(r.primaryType); |
| } |
| } |
| } |
| } |
| if (levelsUp > 0 && !primaryType.isEmpty()) { |
| List<String> parents = new ArrayList<String>(); |
| levelsUp = Math.min(levelsUp, getDepth(path)); |
| String parentPath = path; |
| for (int i = 0; i < levelsUp; i++) { |
| parentPath = getParentPath(parentPath); |
| if (isNodeType(root, parentPath, primaryType)) { |
| parents.add(parentPath); |
| parents.addAll(newArrayList(getParents(root, parentPath, |
| false))); |
| return parents.iterator(); |
| } |
| } |
| } |
| |
| return Collections.emptyIterator(); |
| } |
| |
| private static boolean isNodeType(NodeState root, String path, Set<String> types) { |
| NodeState state = root; |
| for (String p : elements(path)) { |
| if (state.hasChildNode(p)) { |
| state = state.getChildNode(p); |
| } else { |
| return false; |
| } |
| } |
| PropertyState ps = state.getProperty(JCR_PRIMARYTYPE); |
| if (ps == null) { |
| return false; |
| } |
| return types.contains(ps.getValue(STRING)); |
| } |
| |
| // ----- builder methods |
| |
| /** |
| * Include children with the provided name. '*' means include all children |
| * |
| * Note: there is no support for property names yet |
| * |
| */ |
| public SimpleNodeAggregator newRuleWithName(String primaryType, |
| List<String> includes) { |
| aggregates.add(new ChildNameRule(primaryType, includes)); |
| return this; |
| } |
| |
| // ----- aggregation rules |
| |
| private static interface Rule { |
| |
| } |
| |
| private static class ChildNameRule implements Rule { |
| |
| private final String primaryType; |
| private final List<String> includes; |
| |
| ChildNameRule(String primaryType, List<String> includes) { |
| this.primaryType = primaryType; |
| this.includes = includes; |
| } |
| } |
| |
| } |