Author: rombert
Date: Tue Sep 5 12:20:11 2017
New Revision: 1807343
URL: http://svn.apache.org/viewvc?rev=1807343&view=rev
Log:
OAK-6578 - Enhance the UniqueEntryStoreStrategy to return list of
matching values and paths
Add a new queryEntries method to the UniqueIndexStoreStrategy.
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexEntry.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategyTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategy.java
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexEntry.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexEntry.java?rev=1807343&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexEntry.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexEntry.java
Tue Sep 5 12:20:11 2017
@@ -0,0 +1,80 @@
+/*
+ * 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.property.strategy;
+
+/**
+ * An entry in the index
+ *
+ */
+public final class IndexEntry {
+
+ private final String path;
+ private final String propertyValue;
+
+ IndexEntry(String path, String propertyValue) {
+ this.path = path;
+ this.propertyValue = propertyValue;
+
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public String getPropertyValue() {
+ return propertyValue;
+ }
+
+
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((path == null) ? 0 : path.hashCode());
+ result = prime * result + ((propertyValue == null) ? 0 :
propertyValue.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ IndexEntry other = (IndexEntry) obj;
+ if (path == null) {
+ if (other.path != null)
+ return false;
+ } else if (!path.equals(other.path))
+ return false;
+ if (propertyValue == null) {
+ if (other.propertyValue != null)
+ return false;
+ } else if (!propertyValue.equals(other.propertyValue))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+
+ return getClass().getSimpleName() + "# path: " + path + ",
propertyValue: " + propertyValue;
+ }
+}
\ No newline at end of file
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategy.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategy.java?rev=1807343&r1=1807342&r2=1807343&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategy.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategy.java
Tue Sep 5 12:20:11 2017
@@ -119,26 +119,62 @@ public class UniqueEntryStoreStrategy im
@Override
public Iterable<String> query(final Filter filter, final String indexName,
final NodeState indexMeta, final Iterable<String> values) {
+ return query0(filter, indexName, indexMeta, values, new
HitProducer<String>() {
+ @Override
+ public String produce(NodeState indexHit, String pathName) {
+ PropertyState s = indexHit.getProperty("entry");
+ return s.getValue(Type.STRING, 0);
+ }
+ });
+ }
+
+
+
+ /**
+ * Search for a given set of values, returning <tt>IndexEntry</tt> results
+ *
+ * @param filter the filter (can optionally be used for optimized query
execution)
+ * @param indexName the name of the index (for logging)
+ * @param indexMeta the index metadata node (may not be null)
+ * @param values values to look for (null to check for property existence)
+ * @return an iterator of index entries
+ *
+ * @throws UnsupportedOperationException if the operation is not supported
+ */
+ public Iterable<IndexEntry> queryEntries(Filter filter, String indexName,
NodeState indexMeta,
+ Iterable<String> values) {
+ return query0(filter, indexName, indexMeta, values, new
HitProducer<IndexEntry>() {
+ @Override
+ public IndexEntry produce(NodeState indexHit, String pathName) {
+ PropertyState s = indexHit.getProperty("entry");
+ return new IndexEntry(s.getValue(Type.STRING, 0), pathName);
+ }
+ });
+ }
+
+ private <T> Iterable<T> query0(Filter filter, String indexName, NodeState
indexMeta,
+ Iterable<String> values, HitProducer<T> prod) {
final NodeState index = indexMeta.getChildNode(getIndexNodeName());
- return new Iterable<String>() {
+ return new Iterable<T>() {
@Override
- public Iterator<String> iterator() {
+ public Iterator<T> iterator() {
if (values == null) {
- return new Iterator<String>() {
+ return new Iterator<T>() {
Iterator<? extends ChildNodeEntry> it =
index.getChildNodeEntries().iterator();
-
+
@Override
public boolean hasNext() {
return it.hasNext();
}
-
+
@Override
- public String next() {
- PropertyState s =
it.next().getNodeState().getProperty("entry");
- return s.getValue(Type.STRING, 0);
+ public T next() {
+ ChildNodeEntry indexEntry = it.next();
+
+ return prod.produce(indexEntry.getNodeState(),
indexEntry.getName());
}
-
+
@Override
public void remove() {
it.remove();
@@ -146,21 +182,19 @@ public class UniqueEntryStoreStrategy im
};
}
- ArrayList<String> list = new ArrayList<String>();
+ ArrayList<T> list = new ArrayList<>();
for (String p : values) {
NodeState key = index.getChildNode(p);
if (key.exists()) {
// we have an entry for this value, so use it
- PropertyState s = key.getProperty("entry");
- String v = s.getValue(Type.STRING, 0);
- list.add(v);
+ list.add(prod.produce(key, p));
}
}
return list.iterator();
}
};
}
-
+
@Override
public boolean exists(Supplier<NodeBuilder> index, String key) {
return index.get().hasChildNode(key);
@@ -209,4 +243,24 @@ public class UniqueEntryStoreStrategy im
public String getIndexNodeName() {
return indexName;
}
+
+ /**
+ * Creates a specific type of "hit" to return from the query methods
+ *
+ * <p>Use primarily to reduce duplication when the query algorithms
execute mostly the same steps but return different objects.</p>
+ *
+ * @param <T> The type of Hit to produce
+ */
+ private interface HitProducer<T> {
+
+ /**
+ * Invoked when a matching index entry is found
+ *
+ * @param indexHit the index node
+ * @param propertyValue the value of the property
+ * @return the value produced for the specific "hit"
+ */
+ T produce(NodeState indexHit, String propertyValue);
+ }
+
}
Added:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategyTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategyTest.java?rev=1807343&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategyTest.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategyTest.java
Tue Sep 5 12:20:11 2017
@@ -0,0 +1,83 @@
+/*
+ * 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.property.strategy;
+
+import static com.google.common.base.Suppliers.memoize;
+import static com.google.common.collect.Sets.newHashSet;
+import static
org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_CONTENT_NODE_NAME;
+import static
org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.iterableWithSize;
+import static org.junit.Assert.assertThat;
+
+import java.util.Arrays;
+import java.util.Set;
+
+import org.apache.jackrabbit.oak.query.index.FilterImpl;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.hamcrest.Matchers;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.base.Supplier;
+
+public class UniqueEntryStoreStrategyTest {
+
+ private static final Set<String> EMPTY = newHashSet();
+ private String indexName;
+ private NodeBuilder indexMeta;
+ private UniqueEntryStoreStrategy store;
+
+ @Before
+ public void fillIndex() throws Exception {
+
+ store = new UniqueEntryStoreStrategy();
+
+ indexName = "foo";
+
+ NodeState root = EMPTY_NODE;
+ indexMeta = root.builder();
+ Supplier<NodeBuilder> index = memoize(() ->
indexMeta.child(INDEX_CONTENT_NODE_NAME));
+ store.update(index, "/some/node1", null, null, EMPTY,
newHashSet("key1"));
+ store.update(index, "/some/node2", null, null, EMPTY,
newHashSet("key2"));
+ }
+
+ @Test
+ public void queryEntries_All() {
+
+ Iterable<IndexEntry> hits =
store.queryEntries(FilterImpl.newTestInstance(), indexName,
indexMeta.getNodeState(), null);
+
+ assertThat(hits, containsInAnyOrder(new IndexEntry("/some/node1",
"key1"), new IndexEntry("/some/node2", "key2")));
+ }
+
+ @Test
+ public void queryEntries_some() {
+
+ Iterable<IndexEntry> hits =
store.queryEntries(FilterImpl.newTestInstance(), indexName,
indexMeta.getNodeState(), Arrays.asList("key1"));
+
+ assertThat(hits, containsInAnyOrder(new IndexEntry("/some/node1",
"key1")));
+ }
+
+ @Test
+ public void queryEntries_none() {
+
+ Iterable<IndexEntry> hits =
store.queryEntries(FilterImpl.newTestInstance(), indexName,
indexMeta.getNodeState(), Arrays.asList("key3"));
+
+ assertThat(hits, iterableWithSize(0));
+ }
+}