[maven-release-plugin] copy for tag jackrabbit-oak-1.9.9
git-svn-id: https://svn.apache.org/repos/asf/jackrabbit/oak/tags/jackrabbit-oak-1.9.9@1843237 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 16a5b95..38db50f 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -50,6 +50,8 @@
[OAK-7801] - CompositeNodeStore.merge() may trigger conflicting branches
[OAK-7802] - LuceneIndexHelper should extend IndexHelper
[OAK-7805] - getBinaryReferences() may return null when using the split persistence
+ [OAK-7808] - Incorrect facet counts when some results are inaccessible due to ACLs
+ [OAK-7812] - Error running OffRC on Azure because of incorrect parsing
Epic
diff --git a/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/AbstractDataStoreCacheTest.java b/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/AbstractDataStoreCacheTest.java
index db04670..f560b27 100644
--- a/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/AbstractDataStoreCacheTest.java
+++ b/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/AbstractDataStoreCacheTest.java
@@ -54,6 +54,7 @@
import org.apache.jackrabbit.core.data.DataRecord;
import org.apache.jackrabbit.core.data.DataStoreException;
import org.apache.jackrabbit.core.data.util.NamedThreadFactory;
+import org.apache.jackrabbit.oak.commons.FileIOUtils;
import org.apache.jackrabbit.oak.spi.blob.AbstractDataRecord;
import org.apache.jackrabbit.oak.spi.blob.AbstractSharedBackend;
import org.jetbrains.annotations.NotNull;
@@ -111,7 +112,7 @@
static class TestCacheLoader<S, I> extends CacheLoader<String, FileInputStream> {
- protected final File root;
+ protected File root;
public TestCacheLoader(File dir) {
this.root = new File(dir, "datastore");
@@ -169,6 +170,15 @@
this.max = max;
}
+ public TestErrorCacheLoader(File dir, long max, boolean override) {
+ super(dir);
+ if (override) {
+ this.root = dir;
+ }
+
+ this.max = max;
+ }
+
@Override public FileInputStream load(@NotNull String key) throws Exception {
return new ErrorInputStream(getFile(key, root), max);
}
@@ -420,7 +430,7 @@
}
static File copyToFile(InputStream stream, File file) throws IOException {
- FileUtils.copyInputStreamToFile(stream, file);
+ FileIOUtils.copyInputStreamToFile(stream, file);
return file;
}
diff --git a/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/CachingDataStoreTest.java b/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/CachingDataStoreTest.java
index 6bb8ffb..9f84f38 100644
--- a/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/CachingDataStoreTest.java
+++ b/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/CachingDataStoreTest.java
@@ -46,6 +46,7 @@
import org.apache.jackrabbit.oak.spi.blob.BlobOptions;
import org.apache.jackrabbit.oak.stats.DefaultStatisticsProvider;
import org.apache.jackrabbit.oak.stats.StatisticsProvider;
+import org.apache.jackrabbit.util.LazyFileInputStream;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -88,6 +89,8 @@
private TestMemoryBackend backend;
private StatisticsProvider statsProvider;
private TestExecutor listeningExecutor;
+ private String dsPath;
+ private File backendRoot;
@Before
public void setup() throws Exception {
@@ -112,8 +115,8 @@
scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
closer.register(new ExecutorCloser(scheduledExecutor, 500, TimeUnit.MILLISECONDS));
- final File datastoreRoot = folder.newFolder();
- final TestMemoryBackend testBackend = new TestMemoryBackend(datastoreRoot);
+ backendRoot = folder.newFolder();
+ final TestMemoryBackend testBackend = new TestMemoryBackend(backendRoot);
this.backend = testBackend;
dataStore = new AbstractSharedCachingDataStore() {
@@ -131,6 +134,8 @@
dataStore.listeningExecutor = listeningExecutor;
dataStore.schedulerExecutor = scheduledExecutor;
dataStore.executor = sameThreadExecutor();
+ dsPath = new File(root.getAbsolutePath(), "ds").getAbsolutePath();
+ dataStore.setPath(dsPath);
dataStore.init(root.getAbsolutePath());
LOG.info("Finished init");
@@ -155,12 +160,12 @@
dataStore.close();
init(1, (int) cacheSize, 0);
String path = FilenameUtils
- .normalizeNoEndSeparator(new File(root.getAbsolutePath() + "/repository/datastore").getAbsolutePath());
+ .normalizeNoEndSeparator(new File(dsPath).getAbsolutePath());
String home = FilenameUtils.normalizeNoEndSeparator(new File(root.getAbsolutePath()).getAbsolutePath());
dataStore.cache = new CompositeDataStoreCache(path , new File(home), cacheSize, 0,
0,
- new TestErrorCacheLoader(new File(path), 40), new StagingUploader() {
+ new TestErrorCacheLoader(backendRoot, 40, true), new StagingUploader() {
@Override public void write(String id, File file) throws DataStoreException {
backend.write(new DataIdentifier(id), file);
}
@@ -184,13 +189,20 @@
rec = dataStore.addRecord(fin);
}
assertEquals(id, rec.getIdentifier().toString());
- assertFile(rec.getStream(), f, folder);
+ InputStream is = rec.getStream();
+ closer.register(is);
+
+ assertNotNull(is);
+ assertTrue(is instanceof LazyFileInputStream);
+ ((LazyFileInputStream)is).open();
File tmp = new File(new File(path), "tmp");
Collection<File> temp0cacheFiles =
FileUtils.listFiles(tmp, FileFilterUtils.prefixFileFilter("temp0cache"), null);
assertEquals(1, temp0cacheFiles.size());
+ assertFile(is, f, folder, false);
+
LOG.info("Finished loadDirectBackendTemp");
}
@@ -556,14 +568,20 @@
dataStore.close();
}
- private static void assertFile(InputStream is, File org, TemporaryFolder folder)
+ private static void assertFile(InputStream is, File org, TemporaryFolder folder) throws IOException {
+ assertFile(is, org, folder, true);
+ }
+
+ private static void assertFile(InputStream is, File org, TemporaryFolder folder, boolean close)
throws IOException {
try {
File ret = folder.newFile();
- FileUtils.copyInputStreamToFile(is, ret);
+ copyToFile(is, ret);
assertTrue(Files.equal(org, ret));
} finally {
- IOUtils.closeQuietly(is);
+ if (close) {
+ IOUtils.closeQuietly(is);
+ }
}
}
diff --git a/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/FilteredSortedSetDocValuesFacetCounts.java b/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/FilteredSortedSetDocValuesFacetCounts.java
index 05340a5..5b4ec83 100644
--- a/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/FilteredSortedSetDocValuesFacetCounts.java
+++ b/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/FilteredSortedSetDocValuesFacetCounts.java
@@ -19,9 +19,9 @@
package org.apache.jackrabbit.oak.plugins.index.lucene.util;
import java.io.IOException;
-import java.util.HashMap;
import java.util.Map;
+import com.google.common.collect.Maps;
import org.apache.jackrabbit.oak.plugins.index.search.FieldNames;
import org.apache.jackrabbit.oak.spi.query.Filter;
import org.apache.lucene.document.Document;
@@ -34,9 +34,10 @@
import org.apache.lucene.facet.sortedset.SortedSetDocValuesReaderState;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.SortedSetDocValues;
+import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
-import org.apache.lucene.util.BytesRef;
+import org.jetbrains.annotations.NotNull;
/**
* ACL filtered version of {@link SortedSetDocValuesFacetCounts}
@@ -65,9 +66,10 @@
}
LabelAndValue[] labelAndValues = topChildren.labelValues;
+ InaccessibleFacetCountManager inaccessibleFacetCountManager = new InaccessibleFacetCountManager();
for (ScoreDoc scoreDoc : docs.scoreDocs) {
- labelAndValues = filterFacet(scoreDoc.doc, dim, labelAndValues);
+ labelAndValues = filterFacet(scoreDoc.doc, dim, labelAndValues, inaccessibleFacetCountManager);
}
int childCount = labelAndValues.length;
@@ -79,45 +81,82 @@
return new FacetResult(dim, path, value, labelAndValues, childCount);
}
- private LabelAndValue[] filterFacet(int docId, String dimension, LabelAndValue[] labelAndValues) throws IOException {
- boolean filterd = false;
- Map<String, Long> newValues = new HashMap<String, Long>();
-
+ private LabelAndValue[] filterFacet(int docId, String dimension, LabelAndValue[] labelAndValues,
+ InaccessibleFacetCountManager inaccessibleFacetCountManager) throws IOException {
Document document = reader.document(docId);
- SortedSetDocValues docValues = state.getDocValues();
- docValues.setDocument(docId);
// filter using doc values (avoiding requiring stored values)
if (!filter.isAccessible(document.getField(FieldNames.PATH).stringValue() + "/" + dimension)) {
- filterd = true;
- for (LabelAndValue lv : labelAndValues) {
- long existingCount = lv.value.longValue();
- BytesRef key = new BytesRef(FacetsConfig.pathToString(dimension, new String[]{lv.label}));
- long l = docValues.lookupTerm(key);
- if (l >= 0) {
- if (existingCount > 0) {
- newValues.put(lv.label, existingCount - 1);
- } else {
- if (newValues.containsKey(lv.label)) {
- newValues.remove(lv.label);
- }
+ SortedSetDocValues docValues = state.getDocValues();
+ docValues.setDocument(docId);
+ TermsEnum termsEnum = docValues.termsEnum();
+
+ long ord = docValues.nextOrd();
+
+ while (ord != SortedSetDocValues.NO_MORE_ORDS) {
+ termsEnum.seekExact(ord);
+ String facetDVTerm = termsEnum.term().utf8ToString();
+ String [] facetDVDimPaths = FacetsConfig.stringToPath(facetDVTerm);
+
+ for (int i = 1; i < facetDVDimPaths.length; i++) {
+ inaccessibleFacetCountManager.markInaccessbile(facetDVDimPaths[i]);
+ }
+
+ ord = docValues.nextOrd();
+ }
+ }
+
+ return inaccessibleFacetCountManager.updateLabelAndValue(labelAndValues);
+ }
+
+ static class InaccessibleFacetCountManager {
+ Map<String, Long> inaccessbileCounts = Maps.newHashMap();
+
+ void markInaccessbile(@NotNull String label) {
+ Long count = inaccessbileCounts.get(label);
+ if (count == null) {
+ count = 1L;
+ } else {
+ count--;
+ }
+ inaccessbileCounts.put(label, count);
+ }
+
+ LabelAndValue[] updateLabelAndValue(LabelAndValue[] currentLabels) {
+ int numZeros = 0;
+
+ LabelAndValue[] newValues;
+
+ for (int i = 0; i < currentLabels.length; i++) {
+ LabelAndValue lv = currentLabels[i];
+ Long inaccessibleCount = inaccessbileCounts.get(lv.label);
+
+ if (inaccessibleCount != null) {
+ long newValue = lv.value.longValue() - inaccessibleCount;
+
+ if (newValue <= 0) {
+ newValue = 0;
+ numZeros++;
}
+
+ currentLabels[i] = new LabelAndValue(lv.label, newValue);
}
}
- }
- LabelAndValue[] filteredLVs;
- if (filterd) {
- filteredLVs = new LabelAndValue[newValues.size()];
- int i = 0;
- for (Map.Entry<String, Long> entry : newValues.entrySet()) {
- filteredLVs[i] = new LabelAndValue(entry.getKey(), entry.getValue());
- i++;
- }
- } else {
- filteredLVs = labelAndValues;
- }
- return filteredLVs;
+ if (numZeros > 0) {
+ newValues = new LabelAndValue[currentLabels.length - numZeros];
+ int i = 0;
+ for (LabelAndValue lv : currentLabels) {
+ if (lv.value.longValue() > 0) {
+ newValues[i++] = lv;
+ }
+ }
+ } else {
+ newValues = currentLabels;
+ }
+
+ return newValues;
+ }
}
}
\ No newline at end of file
diff --git a/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/FacetTest.java b/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/FacetTest.java
index 3b3fa27..0267f2f 100644
--- a/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/FacetTest.java
+++ b/oak-lucene/src/test/java/org/apache/jackrabbit/oak/jcr/query/FacetTest.java
@@ -26,10 +26,13 @@
import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;
import javax.jcr.query.RowIterator;
+import javax.jcr.security.Privilege;
import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
import org.apache.jackrabbit.core.query.AbstractQueryTest;
-import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants;
import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
import org.apache.jackrabbit.oak.query.facet.FacetResult;
import org.junit.After;
@@ -633,6 +636,110 @@
assertFalse(rows.hasNext());
}
+ public void testNoFacetsIfNoAccess() throws Exception {
+ deny(testRootNode.addNode("test1")).setProperty("jcr:title", "test1");
+ deny(testRootNode.addNode("test2")).addNode("child").setProperty("jcr:title", "test2");
+ deny(testRootNode.addNode("test3").addNode("child")).setProperty("jcr:title", "test3");
+ superuser.save();
+
+ Session anonUser = getHelper().getReadOnlySession();
+ QueryManager queryManager = anonUser.getWorkspace().getQueryManager();
+ Query q = queryManager.createQuery("//*[@jcr:title]/(rep:facet(jcr:title))", Query.XPATH);
+ QueryResult result = q.execute();
+ FacetResult facetResult = new FacetResult(result);
+
+ assertNotNull("facetResult is null", facetResult);
+ assertTrue(facetResult.getDimensions().isEmpty());
+ }
+
+ public void testOnlyAllowedFacetLabelsShowUp() throws Exception {
+ deny(testRootNode.addNode("test1")).setProperty("jcr:title", "test1");
+ deny(testRootNode.addNode("test2")).addNode("child").setProperty("jcr:title", "test2");
+ testRootNode.addNode("test3").addNode("child").setProperty("jcr:title", "test3");
+ superuser.save();
+
+ Session anonUser = getHelper().getReadOnlySession();
+ QueryManager queryManager = anonUser.getWorkspace().getQueryManager();
+ Query q = queryManager.createQuery("//*[@jcr:title]/(rep:facet(jcr:title))", Query.XPATH);
+ QueryResult result = q.execute();
+ FacetResult facetResult = new FacetResult(result);
+
+ assertNotNull("facetResult is null", facetResult);
+ assertEquals("Unexpected number of dimension", 1, facetResult.getFacets("jcr:title").size());
+ FacetResult.Facet facet = facetResult.getFacets("jcr:title").get(0);
+ assertEquals("Unexpected facet label", "test3", facet.getLabel());
+ assertEquals("Unexpected facet count", 1, facet.getCount());
+ }
+
+ public void testInaccessibleFacetCounts() throws Exception {
+ deny(testRootNode.addNode("test1")).setProperty("jcr:title", "test");
+ deny(testRootNode.addNode("test2")).addNode("child").setProperty("jcr:title", "test");
+ testRootNode.addNode("test3").addNode("child").setProperty("jcr:title", "test");
+ testRootNode.addNode("test4").addNode("child").setProperty("jcr:title", "another-test");
+ superuser.save();
+
+ Session anonUser = getHelper().getReadOnlySession();
+ QueryManager queryManager = anonUser.getWorkspace().getQueryManager();
+ Query q = queryManager.createQuery("//*[@jcr:title]/(rep:facet(jcr:title))", Query.XPATH);
+ QueryResult result = q.execute();
+ FacetResult facetResult = new FacetResult(result);
+
+ assertNotNull("facetResult is null", facetResult);
+ assertEquals("Unexpected number of labels", 2, facetResult.getFacets("jcr:title").size());
+ Map<String, Integer> facets = facetResult.getFacets("jcr:title")
+ .stream().collect(Collectors.toMap(FacetResult.Facet::getLabel, FacetResult.Facet::getCount));
+ assertEquals("Unexpected facet count for jcr:title", 1, (int)facets.get("test"));
+ assertEquals("Unexpected facet count for jcr:title", 1, (int)facets.get("another-test"));
+ }
+
+ public void testAllowedSubNodeFacet() throws Exception {
+ allow(
+ deny(testRootNode.addNode("parent")).addNode("child")
+ ).setProperty("jcr:title", "test");
+ superuser.save();
+
+ Session anonUser = getHelper().getReadOnlySession();
+ QueryManager queryManager = anonUser.getWorkspace().getQueryManager();
+ Query q = queryManager.createQuery("//*[@jcr:title]/(rep:facet(jcr:title))", Query.XPATH);
+ QueryResult result = q.execute();
+ FacetResult facetResult = new FacetResult(result);
+
+ assertNotNull("facetResult is null", facetResult);
+ assertEquals("Unexpected number of labels", 1, facetResult.getFacets("jcr:title").size());
+ FacetResult.Facet facet = facetResult.getFacets("jcr:title").get(0);
+ assertEquals("Unexpected facet label", "test", facet.getLabel());
+ assertEquals("Unexpected facet count", 1, facet.getCount());
+ }
+
+ public void testAcRelativeFacetsAccessControl() throws Exception {
+ deny(testRootNode.addNode("test1")).addNode("jc").setProperty("text", "test_1");
+ deny(testRootNode.addNode("test2").addNode("jc")).setProperty("text", "test_2");
+ testRootNode.addNode("test3").addNode("jc").setProperty("text", "test_3");
+ superuser.save();
+
+ Session anonUser = getHelper().getReadOnlySession();
+ QueryManager queryManager = anonUser.getWorkspace().getQueryManager();
+ Query q = queryManager.createQuery("//*[jcr:contains(jc/@text, 'test')]/(rep:facet(jc/text))", Query.XPATH);
+ QueryResult result = q.execute();
+ FacetResult facetResult = new FacetResult(result);
+
+ assertNotNull("facetResult is null", facetResult);
+ assertEquals("Unexpected number of dimension", 1, facetResult.getFacets("jc/text").size());
+ FacetResult.Facet facet = facetResult.getFacets("jc/text").get(0);
+ assertEquals("Unexpected facet label", "test_3", facet.getLabel());
+ assertEquals("Unexpected facet count", 1, facet.getCount());
+ }
+
+ public Node deny(Node node) throws RepositoryException {
+ AccessControlUtils.deny(node, "anonymous", Privilege.JCR_ALL);
+ return node;
+ }
+
+ public Node allow(Node node) throws RepositoryException {
+ AccessControlUtils.allow(node, "anonymous", Privilege.JCR_READ);
+ return node;
+ }
+
private void markIndexForReindex() throws RepositoryException {
superuser.getNode("/oak:index/luceneGlobal").setProperty(REINDEX_PROPERTY_NAME, true);
}
diff --git a/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/tool/ToolUtils.java b/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/tool/ToolUtils.java
index 907a460..1313a2c 100644
--- a/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/tool/ToolUtils.java
+++ b/oak-segment-azure/src/main/java/org/apache/jackrabbit/oak/segment/azure/tool/ToolUtils.java
@@ -95,7 +95,7 @@
switch (storeType) {
case AZURE:
- CloudBlobDirectory cloudBlobDirectory = createCloudBlobDirectory(pathOrUri.substring(3));
+ CloudBlobDirectory cloudBlobDirectory = createCloudBlobDirectory(pathOrUri);
persistence = new AzurePersistence(cloudBlobDirectory);
break;
default: