| /* |
| * 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; |
| |
| import static com.google.common.base.Preconditions.checkArgument; |
| import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE; |
| import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED; |
| import static org.apache.jackrabbit.oak.api.Type.NAME; |
| import static org.apache.jackrabbit.oak.api.Type.NAMES; |
| import static org.apache.jackrabbit.oak.api.Type.STRING; |
| import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.DECLARING_NODE_TYPES; |
| import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME; |
| import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NODE_TYPE; |
| import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.PROPERTY_NAMES; |
| import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME; |
| import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME; |
| import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.UNIQUE_PROPERTY_NAME; |
| |
| import java.util.Collection; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.jcr.RepositoryException; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.Sets; |
| import org.apache.jackrabbit.oak.api.PropertyState; |
| import org.apache.jackrabbit.oak.api.Tree; |
| import org.apache.jackrabbit.oak.api.Type; |
| import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider; |
| import org.apache.jackrabbit.oak.plugins.index.reference.NodeReferenceConstants; |
| import org.apache.jackrabbit.oak.plugins.memory.PropertyStates; |
| import org.apache.jackrabbit.oak.spi.state.NodeBuilder; |
| import org.apache.jackrabbit.oak.spi.state.NodeState; |
| import org.apache.jackrabbit.oak.plugins.tree.TreeUtil; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| /** |
| * TODO document |
| */ |
| public final class IndexUtils { |
| |
| private IndexUtils() { |
| } |
| |
| public static NodeBuilder getOrCreateOakIndex(NodeBuilder root) { |
| NodeBuilder index; |
| if (!root.hasChildNode(INDEX_DEFINITIONS_NAME)) { |
| index = root.child(INDEX_DEFINITIONS_NAME); |
| // TODO: use property node type name |
| index.setProperty(JCR_PRIMARYTYPE, NT_UNSTRUCTURED, NAME); |
| } else { |
| index = root.child(INDEX_DEFINITIONS_NAME); |
| } |
| return index; |
| } |
| |
| /** |
| * Create a new property index definition below the given {@code indexNode}. |
| * |
| * @param index The oak:index node builder |
| * @param indexDefName The name of the new property index. |
| * @param reindex {@code true} if the the reindex flag should be turned on. |
| * @param unique {@code true} if the index is expected the assert property |
| * uniqueness. |
| * @param propertyNames The property names that should be indexed. |
| * @param declaringNodeTypeNames The declaring node type names or {@code null}. |
| * @return the NodeBuilder of the new index definition. |
| */ |
| public static NodeBuilder createIndexDefinition(@NotNull NodeBuilder index, |
| @NotNull String indexDefName, |
| boolean reindex, |
| boolean unique, |
| @NotNull Collection<String> propertyNames, |
| @Nullable Collection<String> declaringNodeTypeNames) { |
| NodeBuilder entry = index.child(indexDefName) |
| .setProperty(JCR_PRIMARYTYPE, INDEX_DEFINITIONS_NODE_TYPE, NAME) |
| .setProperty(TYPE_PROPERTY_NAME, PropertyIndexEditorProvider.TYPE) |
| .setProperty(REINDEX_PROPERTY_NAME, reindex); |
| if (unique) { |
| entry.setProperty(UNIQUE_PROPERTY_NAME, unique); |
| } |
| entry.setProperty(PropertyStates.createProperty(PROPERTY_NAMES, propertyNames, NAMES)); |
| if (declaringNodeTypeNames != null && !declaringNodeTypeNames.isEmpty()) { |
| entry.setProperty(PropertyStates.createProperty(DECLARING_NODE_TYPES, declaringNodeTypeNames, NAMES)); |
| } |
| return entry; |
| } |
| |
| /** |
| * Create a new property2 index definition below the given {@code indexNode}. |
| * |
| * @param indexNode |
| * @param indexDefName |
| * @param unique |
| * @param propertyNames |
| * @param declaringNodeTypeNames |
| */ |
| public static Tree createIndexDefinition(@NotNull Tree indexNode, |
| @NotNull String indexDefName, |
| boolean unique, |
| @NotNull String[] propertyNames, |
| @NotNull String... declaringNodeTypeNames) throws RepositoryException { |
| |
| return createIndexDefinition(indexNode, indexDefName, unique, ImmutableList.copyOf(propertyNames), ImmutableList.copyOf(declaringNodeTypeNames), PropertyIndexEditorProvider.TYPE, null); |
| } |
| |
| /** |
| * Create a new property index definition below the given {@code indexNode} of the provided |
| * {@code propertyIndexType}. |
| * |
| * @param indexNode |
| * @param indexDefName |
| * @param unique |
| * @param propertyNames |
| * @param declaringNodeTypeNames |
| * @param propertyIndexType |
| * @param properties any additional property to be added to the index definition. |
| * @throws RepositoryException |
| */ |
| public static Tree createIndexDefinition(@NotNull Tree indexNode, |
| @NotNull String indexDefName, |
| boolean unique, |
| @NotNull Collection<String> propertyNames, |
| @Nullable Collection<String> declaringNodeTypeNames, |
| @NotNull String propertyIndexType, |
| @Nullable Map<String, String> properties) throws RepositoryException { |
| Tree entry = TreeUtil.getOrAddChild(indexNode, indexDefName, INDEX_DEFINITIONS_NODE_TYPE); |
| entry.setProperty(TYPE_PROPERTY_NAME, propertyIndexType); |
| entry.setProperty(REINDEX_PROPERTY_NAME, true); |
| if (unique) { |
| entry.setProperty(UNIQUE_PROPERTY_NAME, true); |
| } |
| if (declaringNodeTypeNames != null && declaringNodeTypeNames.size() > 0) { |
| entry.setProperty(DECLARING_NODE_TYPES, declaringNodeTypeNames, Type.NAMES); |
| } |
| entry.setProperty(PROPERTY_NAMES, propertyNames, Type.NAMES); |
| |
| if (properties != null) { |
| for (String k : properties.keySet()) { |
| entry.setProperty(k, properties.get(k)); |
| } |
| } |
| return entry; |
| } |
| |
| public static void createReferenceIndex(@NotNull NodeBuilder index) { |
| index.child(NodeReferenceConstants.NAME) |
| .setProperty(JCR_PRIMARYTYPE, INDEX_DEFINITIONS_NODE_TYPE, NAME) |
| .setProperty(TYPE_PROPERTY_NAME, NodeReferenceConstants.TYPE) |
| .setProperty("info", "Oak index for reference lookup."); |
| } |
| |
| public static boolean isIndexNodeType(NodeState state) { |
| PropertyState ps = state.getProperty(JCR_PRIMARYTYPE); |
| return ps != null |
| && ps.getValue(STRING).equals(INDEX_DEFINITIONS_NODE_TYPE); |
| } |
| |
| public static boolean isIndexNodeType(NodeState state, String typeIn) { |
| if (!isIndexNodeType(state)) { |
| return false; |
| } |
| PropertyState type = state.getProperty(TYPE_PROPERTY_NAME); |
| return type != null && !type.isArray() |
| && type.getValue(Type.STRING).equals(typeIn); |
| } |
| |
| /** |
| * Create a new property index definition below the given {@code indexNode} of the provided |
| * {@code propertyIndexType}. |
| * |
| * @param indexNode the oak:index |
| * @param indexDefName the node for the index definition |
| * @param unique true if uniqueness |
| * @param propertyNames the list of properties to be indexed |
| * @param declaringNodeTypeNames |
| * @param propertyIndexType the type of the PropertyIndex |
| * @param properties any additional property to be added to the index definition. |
| * @throws RepositoryException |
| */ |
| public static NodeBuilder createIndexDefinition(@NotNull NodeBuilder indexNode, |
| @NotNull String indexDefName, |
| boolean unique, |
| @NotNull Iterable<String> propertyNames, |
| @Nullable String[] declaringNodeTypeNames, |
| @NotNull String propertyIndexType, |
| Map<String, String> properties) throws RepositoryException { |
| |
| NodeBuilder entry = indexNode.child(indexDefName) |
| .setProperty(JCR_PRIMARYTYPE, INDEX_DEFINITIONS_NODE_TYPE, NAME) |
| .setProperty(TYPE_PROPERTY_NAME, propertyIndexType) |
| .setProperty(REINDEX_PROPERTY_NAME, false); |
| if (unique) { |
| entry.setProperty(UNIQUE_PROPERTY_NAME, unique); |
| } |
| entry.setProperty(PropertyStates.createProperty(PROPERTY_NAMES, propertyNames, NAMES)); |
| if (declaringNodeTypeNames != null && declaringNodeTypeNames.length > 0) { |
| entry.setProperty(PropertyStates.createProperty(DECLARING_NODE_TYPES, |
| declaringNodeTypeNames, NAMES)); |
| } |
| // additional properties |
| if (properties != null) { |
| for (String k : properties.keySet()) { |
| entry.setProperty(k, properties.get(k)); |
| } |
| } |
| return entry; |
| } |
| |
| @Nullable |
| public static String getAsyncLaneName(NodeState idxState, String indexPath) { |
| return getAsyncLaneName(idxState, indexPath, idxState.getProperty(IndexConstants.ASYNC_PROPERTY_NAME)); |
| } |
| |
| @Nullable |
| public static String getAsyncLaneName(NodeState idxState, String indexPath, PropertyState async) { |
| if (async != null) { |
| Set<String> asyncNames = Sets.newHashSet(async.getValue(Type.STRINGS)); |
| asyncNames.remove(IndexConstants.INDEXING_MODE_NRT); |
| asyncNames.remove(IndexConstants.INDEXING_MODE_SYNC); |
| checkArgument(!asyncNames.isEmpty(), "No valid async name found for " + |
| "index [%s], definition %s", indexPath, idxState); |
| return Iterables.getOnlyElement(asyncNames); |
| } |
| return null; |
| } |
| } |