blob: b0218b97148419489f476c9bc7e13dfb27c66e54 [file] [log] [blame]
/*
* 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.search;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import javax.jcr.PropertyType;
import javax.jcr.Repository;
import org.apache.commons.io.IOUtils;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.api.JackrabbitRepository;
import org.apache.jackrabbit.oak.api.Blob;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Root;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.IndexingMode;
import org.apache.jackrabbit.oak.plugins.index.search.util.IndexHelper;
import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
import org.apache.jackrabbit.oak.plugins.memory.ModifiedNodeState;
import org.apache.jackrabbit.oak.plugins.name.NamespaceEditorProvider;
import org.apache.jackrabbit.oak.plugins.nodetype.TypeEditorProvider;
import org.apache.jackrabbit.oak.plugins.nodetype.write.NodeTypeRegistry;
import org.apache.jackrabbit.oak.plugins.tree.factories.RootFactory;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.commit.CompositeEditorProvider;
import org.apache.jackrabbit.oak.spi.commit.Editor;
import org.apache.jackrabbit.oak.spi.commit.EditorHook;
import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
import org.apache.jackrabbit.oak.spi.state.ApplyDiff;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableSet.of;
import static org.apache.jackrabbit.JcrConstants.JCR_CONTENT;
import static org.apache.jackrabbit.oak.api.Type.STRINGS;
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.REINDEX_PROPERTY_NAME;
import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
import static org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
public class TestUtil {
private static final AtomicInteger COUNTER = new AtomicInteger();
public static final String NT_TEST = "oak:TestNode";
public static final String TEST_NODE_TYPE = "[oak:TestNode]\n" +
" - * (UNDEFINED) multiple\n" +
" - * (UNDEFINED)\n" +
" + * (nt:base) = oak:TestNode VERSION";
static void useV2(NodeBuilder idxNb) {
if (!IndexFormatVersion.getDefault().isAtLeast(IndexFormatVersion.V2)) {
idxNb.setProperty(FulltextIndexConstants.COMPAT_MODE, IndexFormatVersion.V2.getVersion());
}
}
static void useV2(Tree idxTree) {
if (!IndexFormatVersion.getDefault().isAtLeast(IndexFormatVersion.V2)) {
idxTree.setProperty(FulltextIndexConstants.COMPAT_MODE, IndexFormatVersion.V2.getVersion());
}
}
public static NodeBuilder newFTIndexDefinitionV2(
@NotNull NodeBuilder index, @NotNull String name, String type,
@Nullable Set<String> propertyTypes) {
NodeBuilder nb = IndexHelper.newFTIndexDefinition(index, name, type, propertyTypes, null, null, null);
useV2(nb);
return nb;
}
public static Tree enableForFullText(Tree props, String propName) {
return enableForFullText(props, propName, false);
}
public static Tree enableForFullText(Tree props, String propName, boolean regex) {
Tree prop = props.addChild(unique("prop"));
prop.setProperty(FulltextIndexConstants.PROP_NAME, propName);
prop.setProperty(FulltextIndexConstants.PROP_PROPERTY_INDEX, true);
prop.setProperty(FulltextIndexConstants.PROP_IS_REGEX, regex);
prop.setProperty(FulltextIndexConstants.PROP_NODE_SCOPE_INDEX, true);
prop.setProperty(FulltextIndexConstants.PROP_ANALYZED, true);
prop.setProperty(FulltextIndexConstants.PROP_USE_IN_EXCERPT, true);
prop.setProperty(FulltextIndexConstants.PROP_USE_IN_SPELLCHECK, true);
return prop;
}
public static Tree enableForOrdered(Tree props, String propName) {
Tree prop = enablePropertyIndex(props, propName, false);
prop.setProperty("ordered", true);
return prop;
}
public static Tree enablePropertyIndex(Tree props, String propName, boolean regex) {
Tree prop = props.addChild(unique("prop"));
prop.setProperty(FulltextIndexConstants.PROP_NAME, propName);
prop.setProperty(FulltextIndexConstants.PROP_PROPERTY_INDEX, true);
prop.setProperty(FulltextIndexConstants.PROP_IS_REGEX, regex);
prop.setProperty(FulltextIndexConstants.PROP_NODE_SCOPE_INDEX, false);
prop.setProperty(FulltextIndexConstants.PROP_ANALYZED, false);
return prop;
}
public static Tree enableFunctionIndex(Tree props, String function) {
Tree prop = props.addChild(unique("prop"));
prop.setProperty(FulltextIndexConstants.PROP_FUNCTION, function);
return prop;
}
public static AggregatorBuilder newNodeAggregator(Tree indexDefn){
return new AggregatorBuilder(indexDefn);
}
public static Tree newRulePropTree(Tree indexDefn, String typeName){
Tree rules = indexDefn.addChild(FulltextIndexConstants.INDEX_RULES);
rules.setOrderableChildren(true);
Tree rule = rules.addChild(typeName);
Tree props = rule.addChild(FulltextIndexConstants.PROP_NODE);
props.setOrderableChildren(true);
return props;
}
public static NodeBuilder child(NodeBuilder nb, String path) {
for (String name : PathUtils.elements(checkNotNull(path))) {
nb = nb.child(name);
}
return nb;
}
static class AggregatorBuilder {
private final Tree aggs;
private AggregatorBuilder(Tree indexDefn) {
this.aggs = indexDefn.addChild(FulltextIndexConstants.AGGREGATES);
}
AggregatorBuilder newRuleWithName(String primaryType,
List<String> includes){
Tree agg = aggs.addChild(primaryType);
for (String include : includes){
agg.addChild(unique("include")).setProperty(FulltextIndexConstants.AGG_PATH, include);
}
return this;
}
}
static String unique(String name){
return name + COUNTER.getAndIncrement();
}
public static NodeBuilder registerTestNodeType(NodeBuilder builder){
registerNodeType(builder, TEST_NODE_TYPE);
return builder;
}
public static void registerNodeType(NodeBuilder builder, String nodeTypeDefn){
//Taken from org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent
NodeState base = ModifiedNodeState.squeeze(builder.getNodeState());
NodeStore store = new MemoryNodeStore(base);
Root root = RootFactory.createSystemRoot(
store, new EditorHook(new CompositeEditorProvider(
new NamespaceEditorProvider(),
new TypeEditorProvider())), null, null, null);
NodeTypeRegistry.register(root, IOUtils.toInputStream(nodeTypeDefn), "test node types");
NodeState target = store.getRoot();
target.compareAgainstBaseState(base, new ApplyDiff(builder));
}
public static Tree createNodeWithType(Tree t, String nodeName, String typeName){
t = t.addChild(nodeName);
t.setProperty(JcrConstants.JCR_PRIMARYTYPE, typeName, Type.NAME);
return t;
}
public static NodeBuilder createNodeWithType(NodeBuilder builder, String nodeName, String typeName){
builder = builder.child(nodeName);
builder.setProperty(JcrConstants.JCR_PRIMARYTYPE, typeName, Type.NAME);
return builder;
}
public static Tree createFileNode(Tree tree, String name, Blob content, String mimeType){
Tree fileNode = tree.addChild(name);
fileNode.setProperty(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_FILE, Type.NAME);
Tree jcrContent = fileNode.addChild(JCR_CONTENT);
jcrContent.setProperty(JcrConstants.JCR_DATA, content);
jcrContent.setProperty(JcrConstants.JCR_MIMETYPE, mimeType);
return jcrContent;
}
public static Tree createFulltextIndex(Tree index, String name, String type) throws CommitFailedException {
Tree def = index.addChild(INDEX_DEFINITIONS_NAME).addChild(name);
def.setProperty(JcrConstants.JCR_PRIMARYTYPE,
INDEX_DEFINITIONS_NODE_TYPE, Type.NAME);
def.setProperty(TYPE_PROPERTY_NAME, type);
def.setProperty(REINDEX_PROPERTY_NAME, true);
def.setProperty(createProperty(FulltextIndexConstants.INCLUDE_PROPERTY_TYPES,
of(PropertyType.TYPENAME_STRING, PropertyType.TYPENAME_BINARY), STRINGS));
return index.getChild(INDEX_DEFINITIONS_NAME).getChild(name);
}
public static void shutdown(Repository repository) {
if (repository instanceof JackrabbitRepository) {
((JackrabbitRepository) repository).shutdown();
}
}
public static NodeBuilder enableIndexingMode(NodeBuilder builder, IndexingMode indexingMode){
builder.setProperty(createAsyncProperty(indexingMode));
return builder;
}
public static Tree enableIndexingMode(Tree tree, IndexingMode indexingMode){
tree.setProperty(createAsyncProperty(indexingMode));
return tree;
}
private static PropertyState createAsyncProperty(String indexingMode) {
return createProperty(IndexConstants.ASYNC_PROPERTY_NAME, of(indexingMode , "async"), STRINGS);
}
private static PropertyState createAsyncProperty(IndexingMode indexingMode) {
switch(indexingMode) {
case SYNC :
return createAsyncProperty(indexingMode.asyncValueName());
case ASYNC:
return createProperty(IndexConstants.ASYNC_PROPERTY_NAME, of("async"), STRINGS);
default:
throw new IllegalArgumentException("Unknown mode " + indexingMode);
}
}
public static class OptionalEditorProvider implements EditorProvider {
public EditorProvider delegate;
@Override
public Editor getRootEditor(NodeState before, NodeState after, NodeBuilder builder, CommitInfo info) throws CommitFailedException {
if (delegate != null){
return delegate.getRootEditor(before, after, builder, info);
}
return null;
}
}
}