Author: angela
Date: Thu May 3 16:51:10 2018
New Revision: 1830843
URL: http://svn.apache.org/viewvc?rev=1830843&view=rev
Log:
OAK-7343 : Improvements to PermissionEntryProviderImpl
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/NumEntries.java
(with props)
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCache.java
(with props)
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCacheBuilder.java
(with props)
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/EmptyPermissionCacheTest.java
(with props)
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/NumEntriesTest.java
(with props)
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCacheBuilderTest.java
(with props)
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryCacheTest.java
(with props)
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImplTest.java
(with props)
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PrincipalPermissionEntriesTest.java
(with props)
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/MountPermissionProvider.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryCache.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProviderImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PrincipalPermissionEntries.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/MountPermissionStoreTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProviderImplTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java
jackrabbit/oak/trunk/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/PermissionConstants.java
jackrabbit/oak/trunk/oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/package-info.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java?rev=1830843&r1=1830842&r2=1830843&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java
Thu May 3 16:51:10 2018
@@ -110,9 +110,8 @@ final class CompiledPermissionImpl imple
}
}
- PermissionEntryCache cache = new PermissionEntryCache();
- userStore = new PermissionEntryProviderImpl(store, cache, userNames,
options);
- groupStore = new PermissionEntryProviderImpl(store, cache, groupNames,
options);
+ userStore = new PermissionEntryProviderImpl(store, userNames, options);
+ groupStore = new PermissionEntryProviderImpl(store, groupNames,
options);
typeProvider = new TreeTypeProvider(ctx);
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/MountPermissionProvider.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/MountPermissionProvider.java?rev=1830843&r1=1830842&r2=1830843&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/MountPermissionProvider.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/MountPermissionProvider.java
Thu May 3 16:51:10 2018
@@ -16,16 +16,11 @@
*/
package org.apache.jackrabbit.oak.security.authorization.permission;
-import static com.google.common.collect.Lists.newArrayList;
-
import java.security.Principal;
import java.util.Collection;
import java.util.List;
import java.util.Set;
-
-import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
import org.apache.jackrabbit.oak.api.Root;
import org.apache.jackrabbit.oak.commons.LongUtils;
@@ -36,6 +31,8 @@ import org.apache.jackrabbit.oak.spi.sec
import org.apache.jackrabbit.oak.spi.security.Context;
import
org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
+import static com.google.common.collect.Lists.newArrayList;
+
public class MountPermissionProvider extends PermissionProviderImpl {
@Nonnull
@@ -79,12 +76,12 @@ public class MountPermissionProvider ext
this.stores = stores;
}
- @CheckForNull
+ @Nonnull
@Override
- public Collection<PermissionEntry> load(@Nullable
Collection<PermissionEntry> entries, @Nonnull String principalName,
- @Nonnull String path) {
+ public Collection<PermissionEntry> load(@Nonnull String principalName,
+ @Nonnull String path) {
for (PermissionStoreImpl store : stores) {
- Collection<PermissionEntry> col = store.load(null,
principalName, path);
+ Collection<PermissionEntry> col = store.load(principalName,
path);
if (col != null && !col.isEmpty()) {
return col;
}
@@ -97,22 +94,32 @@ public class MountPermissionProvider ext
public PrincipalPermissionEntries load(@Nonnull String principalName) {
PrincipalPermissionEntries ppe = new PrincipalPermissionEntries();
for (PermissionStoreImpl store : stores) {
-
ppe.getEntries().putAll(store.load(principalName).getEntries());
+ ppe.putAllEntries(store.load(principalName).getEntries());
}
ppe.setFullyLoaded(true);
return ppe;
}
+ @Nonnull
@Override
- public long getNumEntries(@Nonnull String principalName, long max) {
+ public NumEntries getNumEntries(@Nonnull String principalName, long
max) {
long num = 0;
+ boolean isExact = true;
for (PermissionStoreImpl store : stores) {
- num = LongUtils.safeAdd(num,
store.getNumEntries(principalName, max));
- if (num >= max) {
+ NumEntries ne = store.getNumEntries(principalName, max);
+ num = LongUtils.safeAdd(num, ne.size);
+ if (!ne.isExact) {
+ isExact = false;
+ }
+ // if any of the stores doesn't reveal the exact number and max
+ // is reached, stop asking the remaining stores.
+ // as long as every store is reporting the exact number
continue
+ // in order to (possibly) be able to return the exact number.
+ if (num >= max && !isExact) {
break;
}
}
- return num;
+ return NumEntries.valueOf(num, isExact);
}
@Override
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/NumEntries.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/NumEntries.java?rev=1830843&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/NumEntries.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/NumEntries.java
Thu May 3 16:51:10 2018
@@ -0,0 +1,60 @@
+/*
+ * 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.security.authorization.permission;
+
+import com.google.common.base.Objects;
+
+final class NumEntries {
+
+ static final NumEntries ZERO = new NumEntries(0, true);
+
+ final long size;
+ final boolean isExact;
+
+ private NumEntries(long size, boolean isExact) {
+ this.size = size;
+ this.isExact = isExact;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(size, isExact);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof NumEntries) {
+ NumEntries other = (NumEntries) obj;
+ return size == other.size && isExact == other.isExact;
+ } else {
+ return false;
+ }
+ }
+
+ static NumEntries valueOf(long size, boolean isExact) {
+ if (size == 0) {
+ // if size is zero we assume that this is the correct value
+ // irrespective of the isExact flag.
+ return ZERO;
+ } else {
+ return new NumEntries(size, isExact);
+ }
+ }
+}
\ No newline at end of file
Propchange:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/NumEntries.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCache.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCache.java?rev=1830843&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCache.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCache.java
Thu May 3 16:51:10 2018
@@ -0,0 +1,29 @@
+/*
+ * 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.security.authorization.permission;
+
+import java.util.Collection;
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.Tree;
+
+interface PermissionCache {
+
+ Collection<PermissionEntry> getEntries(@Nonnull String path);
+
+ Collection<PermissionEntry> getEntries(@Nonnull Tree accessControlledTree);
+}
\ No newline at end of file
Propchange:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCache.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCacheBuilder.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCacheBuilder.java?rev=1830843&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCacheBuilder.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCacheBuilder.java
Thu May 3 16:51:10 2018
@@ -0,0 +1,207 @@
+/*
+ * 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.security.authorization.permission;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.commons.LongUtils;
+import
org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
+
+import static com.google.common.base.Preconditions.checkState;
+
+final class PermissionCacheBuilder {
+
+ private static final long MAX_PATHS_SIZE = 10;
+
+ private final PermissionStore store;
+ private final PermissionEntryCache peCache;
+
+ private Set<String> existingNames;
+ private boolean usePathEntryMap;
+
+ private boolean initialized = false;
+
+ PermissionCacheBuilder(@Nonnull PermissionStore store) {
+ this.store = store;
+ this.peCache = new PermissionEntryCache();
+ }
+
+ boolean init(@Nonnull Set<String> principalNames, long maxSize) {
+ existingNames = new HashSet<>();
+ long cnt = 0;
+ for (String name : principalNames) {
+ NumEntries ne = store.getNumEntries(name, maxSize);
+ long n = ne.size;
+ /*
+ if getNumEntries (n) returns a number bigger than 0, we
+ remember this principal name int the 'existingNames' set
+ */
+ if (n > 0) {
+ existingNames.add(name);
+ if (n <= MAX_PATHS_SIZE) {
+ peCache.getFullyLoadedEntries(store, name);
+ } else {
+ long expectedSize = (ne.isExact) ? n : Long.MAX_VALUE;
+ peCache.init(name, expectedSize);
+ }
+ }
+ /*
+ Estimate the total number of access controlled paths (cnt) defined
+ for the given set of principals in order to be able to determine if
+ the pathEntryMap should be loaded upfront.
+ Note however that cache.getNumEntries (n) may return Long.MAX_VALUE
+ if the underlying implementation does not know the exact value, and
+ the child node count is higher than maxSize (see OAK-2465).
+ */
+ if (cnt < Long.MAX_VALUE) {
+ if (Long.MAX_VALUE == n) {
+ cnt = Long.MAX_VALUE;
+ } else {
+ cnt = LongUtils.safeAdd(cnt, n);
+ }
+ }
+ }
+
+ usePathEntryMap = (cnt > 0 && cnt < maxSize);
+ initialized = true;
+ return existingNames.isEmpty();
+ }
+
+ PermissionCache build() {
+ checkState(initialized);
+ if (existingNames.isEmpty()) {
+ return EmptyCache.INSTANCE;
+ }
+ if (usePathEntryMap) {
+ // the total number of access controlled paths is smaller that
maxSize,
+ // so we can load all permission entries for all principals having
+ // any entries right away into the pathEntryMap
+ Map<String, Collection<PermissionEntry>> pathEntryMap = new
HashMap<>();
+ for (String name : existingNames) {
+ PrincipalPermissionEntries ppe =
peCache.getFullyLoadedEntries(store, name);
+ for (Map.Entry<String, Collection<PermissionEntry>> e :
ppe.getEntries().entrySet()) {
+ String path = e.getKey();
+ Collection<PermissionEntry> pathEntries =
pathEntryMap.get(path);
+ if (pathEntries == null) {
+ pathEntries = new TreeSet(e.getValue());
+ pathEntryMap.put(path, pathEntries);
+ } else {
+ pathEntries.addAll(e.getValue());
+ }
+ }
+ }
+ if (pathEntryMap.isEmpty()) {
+ return EmptyCache.INSTANCE;
+ } else {
+ return new PathEntryMapCache(pathEntryMap);
+ }
+ } else {
+ return new DefaultPermissionCache(store, peCache, existingNames);
+ }
+
+ }
+
+ //------------------------------------< PermissionCache Implementations
>---
+ /**
+ * Default implementation of {@code PermissionCache} wrapping the
+ * {@code PermissionEntryCache}, which was previously hold as shared field
+ * inside the {@code PermissionEntryProviderImpl}
+ */
+ private static final class DefaultPermissionCache implements
PermissionCache {
+ private final PermissionStore store;
+ private final PermissionEntryCache cache;
+ private final Set<String> existingNames;
+
+ DefaultPermissionCache(@Nonnull PermissionStore store, @Nonnull
PermissionEntryCache cache, Set<String> existingNames) {
+ this.store = store;
+ this.cache = cache;
+ this.existingNames = existingNames;
+ }
+
+ @Override
+ public Collection<PermissionEntry> getEntries(@Nonnull String path) {
+ Collection<PermissionEntry> ret = new TreeSet();
+ for (String name : existingNames) {
+ cache.load(store, ret, name, path);
+ }
+ return ret;
+ }
+
+ @Override
+ public Collection<PermissionEntry> getEntries(@Nonnull Tree
accessControlledTree) {
+ return
(accessControlledTree.hasChild(AccessControlConstants.REP_POLICY)) ?
+ getEntries(accessControlledTree.getPath()) :
+ Collections.<PermissionEntry>emptyList();
+ }
+ }
+
+ /**
+ * Fixed size implementation of {@code PermissionCache} that holds a map
+ * containing all existing entries that in this case have been read eagerly
+ * upfront. This implementation replaces the optional {@code pathEntryMap}
+ * previously present inside the the {@code PermissionEntryProviderImpl}.
+ */
+ private static final class PathEntryMapCache implements PermissionCache {
+ private final Map<String, Collection<PermissionEntry>> pathEntryMap;
+
+ PathEntryMapCache(Map<String, Collection<PermissionEntry>>
pathEntryMap) {
+ this.pathEntryMap = pathEntryMap;
+ }
+
+ @Override
+ public Collection<PermissionEntry> getEntries(@Nonnull String path) {
+ Collection<PermissionEntry> entries = pathEntryMap.get(path);
+ return (entries != null) ? entries :
Collections.<PermissionEntry>emptyList();
+ }
+
+ @Override
+ public Collection<PermissionEntry> getEntries(@Nonnull Tree
accessControlledTree) {
+ Collection<PermissionEntry> entries =
pathEntryMap.get(accessControlledTree.getPath());
+ return (entries != null) ? entries :
Collections.<PermissionEntry>emptyList();
+ }
+ }
+
+ /**
+ * Empty implementation of {@code PermissionCache} for those cases where
+ * for a given (possibly empty) set of principals no permission entries are
+ * present.
+ */
+ private static final class EmptyCache implements PermissionCache {
+
+ private static final PermissionCache INSTANCE = new EmptyCache();
+
+ @Override
+ public Collection<PermissionEntry> getEntries(@Nonnull String path) {
+ return Collections.<PermissionEntry>emptyList();
+ }
+
+ @Override
+ public Collection<PermissionEntry> getEntries(@Nonnull Tree
accessControlledTree) {
+ return Collections.<PermissionEntry>emptyList();
+ }
+ }
+
+}
\ No newline at end of file
Propchange:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCacheBuilder.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryCache.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryCache.java?rev=1830843&r1=1830842&r2=1830843&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryCache.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryCache.java
Thu May 3 16:51:10 2018
@@ -20,55 +20,36 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
import javax.annotation.Nonnull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
* {@code PermissionEntryCache} caches the permission entries of principals.
* The cache is held locally for each session and contains a version of the
principal permission
* entries of the session that read them last.
- *
- * TODO:
- * - report cache usage metrics
- * - limit size of local caches based on ppe sizes. the current implementation
loads all ppes. this can get a memory
- * problem, as well as a performance problem for principals with many
entries. principals with many entries must
- * fallback to the direct store.load() methods when providing the entries.
if those principals with many entries
- * are used often, they might get elected to live in the global cache;
memory permitting.
*/
class PermissionEntryCache {
- private final Map<String, PrincipalPermissionEntries> entries = new
HashMap<String, PrincipalPermissionEntries>();
+ private static final Logger log =
LoggerFactory.getLogger(PermissionEntryCache.class);
+
+ private final Map<String, PrincipalPermissionEntries> entries = new
HashMap<>();
@Nonnull
- PrincipalPermissionEntries getEntries(@Nonnull PermissionStore store,
- @Nonnull String
principalName) {
+ PrincipalPermissionEntries getFullyLoadedEntries(@Nonnull PermissionStore
store,
+ @Nonnull String
principalName) {
PrincipalPermissionEntries ppe = entries.get(principalName);
- if (ppe == null) {
+ if (ppe == null || !ppe.isFullyLoaded()) {
ppe = store.load(principalName);
entries.put(principalName, ppe);
- } else {
- if (!ppe.isFullyLoaded()) {
- ppe = store.load(principalName);
- entries.put(principalName, ppe);
- }
}
return ppe;
}
- void load(@Nonnull PermissionStore store,
- @Nonnull Map<String, Collection<PermissionEntry>> pathEntryMap,
- @Nonnull String principalName) {
- // todo: conditionally load entries if too many
- PrincipalPermissionEntries ppe = getEntries(store, principalName);
- for (Map.Entry<String, Collection<PermissionEntry>> e:
ppe.getEntries().entrySet()) {
- Collection<PermissionEntry> pathEntries =
pathEntryMap.get(e.getKey());
- if (pathEntries == null) {
- pathEntries = new TreeSet<PermissionEntry>(e.getValue());
- pathEntryMap.put(e.getKey(), pathEntries);
- } else {
- pathEntries.addAll(e.getValue());
- }
+ void init(@Nonnull String principalName, long expectedSize) {
+ if (!entries.containsKey(principalName)) {
+ entries.put(principalName, new
PrincipalPermissionEntries(expectedSize));
}
}
@@ -76,26 +57,29 @@ class PermissionEntryCache {
@Nonnull Collection<PermissionEntry> ret,
@Nonnull String principalName,
@Nonnull String path) {
- PrincipalPermissionEntries ppe = entries.get(principalName);
- if (ppe == null) {
- ppe = new PrincipalPermissionEntries();
- entries.put(principalName, ppe);
- }
- Collection<PermissionEntry> pes = ppe.getEntries().get(path);
- if (pes == null) {
- pes = store.load(null, principalName, path);
- if (pes == null) {
- pes = Collections.emptySet();
+ if (entries.containsKey(principalName)) {
+ PrincipalPermissionEntries ppe = entries.get(principalName);
+ Collection<PermissionEntry> pes = ppe.getEntriesByPath(path);
+ if (ppe.isFullyLoaded() || pes != null) {
+ // no need to read from store
+ if (pes != null) {
+ ret.addAll(pes);
+ }
} else {
- ret.addAll(pes);
+ // read entries for path from store
+ pes = store.load(principalName, path);
+ if (pes == null) {
+ // nothing to add to the result collection 'ret'.
+ // nevertheless, remember the absence of any permission
entries
+ // in the cache to avoid reading from store again.
+ ppe.putEntriesByPath(path, Collections.emptySet());
+ } else {
+ ppe.putEntriesByPath(path, pes);
+ ret.addAll(pes);
+ }
}
- ppe.getEntries().put(path, pes);
} else {
- ret.addAll(pes);
+ log.error("Failed to load entries for principal '%s' at path %s",
principalName, path);
}
}
-
- void flush(@Nonnull Set<String> principalNames) {
- entries.keySet().removeAll(principalNames);
- }
}
\ No newline at end of file
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProviderImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProviderImpl.java?rev=1830843&r1=1830842&r2=1830843&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProviderImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProviderImpl.java
Thu May 3 16:51:10 2018
@@ -18,20 +18,14 @@ package org.apache.jackrabbit.oak.securi
import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
-import java.util.Map;
import java.util.Set;
-import java.util.TreeSet;
import javax.annotation.Nonnull;
import com.google.common.base.Strings;
import org.apache.jackrabbit.commons.iterator.AbstractLazyIterator;
import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.commons.LongUtils;
import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
-import
org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
class PermissionEntryProviderImpl implements PermissionEntryProvider {
@@ -45,84 +39,41 @@ class PermissionEntryProviderImpl implem
*/
private final Set<String> principalNames;
- /**
- * The set of principal names for which the store contains any permission
- * entries. This set is equals or just a subset of the {@code
principalNames}
- * defined above. The methods collecting the entries will shortcut in case
- * this set is empty and thus no permission entries exist for the specified
- * set of principal.
- */
- private final Set<String> existingNames = new HashSet<String>();
-
private final PermissionStore store;
- private final PermissionEntryCache cache;
-
private final long maxSize;
- private Map<String, Collection<PermissionEntry>> pathEntryMap;
+ /**
+ * Flag to indicate if the the store contains any permission entries for
the
+ * given set of principal names.
+ */
+ private boolean noExistingNames;
+
+ private PermissionCache permissionCache;
- PermissionEntryProviderImpl(@Nonnull PermissionStore store, @Nonnull
PermissionEntryCache cache,
- @Nonnull Set<String> principalNames, @Nonnull
ConfigurationParameters options) {
+ PermissionEntryProviderImpl(@Nonnull PermissionStore store, @Nonnull
Set<String> principalNames, @Nonnull ConfigurationParameters options) {
this.store = store;
- this.cache = cache;
this.principalNames = Collections.unmodifiableSet(principalNames);
this.maxSize = options.getConfigValue(EAGER_CACHE_SIZE_PARAM,
DEFAULT_SIZE);
init();
}
private void init() {
- long cnt = 0;
- existingNames.clear();
- for (String name : principalNames) {
- long n = store.getNumEntries(name, maxSize);
- /*
- if cache.getNumEntries (n) returns a number bigger than 0, we
- remember this principal name int the 'existingNames' set
- */
- if (n > 0) {
- existingNames.add(name);
- }
- /*
- Calculate the total number of permission entries (cnt) defined for
the
- given set of principals in order to be able to determine if the
cache
- should be loaded upfront.
- Note however that cache.getNumEntries (n) may return Long.MAX_VALUE
- if the underlying implementation does not know the exact value, and
- the child node count is higher than maxSize (see OAK-2465).
- */
- if (cnt < Long.MAX_VALUE) {
- if (Long.MAX_VALUE == n) {
- cnt = Long.MAX_VALUE;
- } else {
- cnt = LongUtils.safeAdd(cnt, n);
- }
- }
- }
-
- if (cnt > 0 && cnt < maxSize) {
- // the total number of entries is smaller that maxSize, so we can
- // cache all entries for all principals having any entries right
away
- pathEntryMap = new HashMap<String, Collection<PermissionEntry>>();
- for (String name : existingNames) {
- cache.load(store, pathEntryMap, name);
- }
- } else {
- pathEntryMap = null;
- }
+ PermissionCacheBuilder builder = new PermissionCacheBuilder(store);
+ noExistingNames = builder.init(principalNames, maxSize);
+ permissionCache = builder.build();
}
//--------------------------------------------< PermissionEntryProvider
>---
@Override
public void flush() {
- cache.flush(principalNames);
init();
}
@Override
@Nonnull
public Iterator<PermissionEntry> getEntryIterator(@Nonnull EntryPredicate
predicate) {
- if (existingNames.isEmpty()) {
+ if (noExistingNames) {
return Collections.emptyIterator();
} else {
return new EntryIterator(predicate);
@@ -132,38 +83,13 @@ class PermissionEntryProviderImpl implem
@Override
@Nonnull
public Collection<PermissionEntry> getEntries(@Nonnull Tree
accessControlledTree) {
- if (existingNames.isEmpty()) {
- return Collections.emptyList();
- } else if (pathEntryMap != null) {
- Collection<PermissionEntry> entries =
pathEntryMap.get(accessControlledTree.getPath());
- return (entries != null) ? entries :
Collections.<PermissionEntry>emptyList();
- } else {
- return
(accessControlledTree.hasChild(AccessControlConstants.REP_POLICY)) ?
- loadEntries(accessControlledTree.getPath()) :
- Collections.<PermissionEntry>emptyList();
- }
+ return permissionCache.getEntries(accessControlledTree);
}
//------------------------------------------------------------< private
>---
@Nonnull
private Collection<PermissionEntry> getEntries(@Nonnull String path) {
- if (existingNames.isEmpty()) {
- return Collections.emptyList();
- } else if (pathEntryMap != null) {
- Collection<PermissionEntry> entries = pathEntryMap.get(path);
- return (entries != null) ? entries :
Collections.<PermissionEntry>emptyList();
- } else {
- return loadEntries(path);
- }
- }
-
- @Nonnull
- private Collection<PermissionEntry> loadEntries(@Nonnull String path) {
- Collection<PermissionEntry> ret = new TreeSet<PermissionEntry>();
- for (String name : existingNames) {
- cache.load(store, ret, name, path);
- }
- return ret;
+ return permissionCache.getEntries(path);
}
private final class EntryIterator extends
AbstractLazyIterator<PermissionEntry> {
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java?rev=1830843&r1=1830842&r2=1830843&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java
Thu May 3 16:51:10 2018
@@ -20,7 +20,6 @@ import java.util.Collection;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
import org.apache.jackrabbit.oak.api.Root;
@@ -33,22 +32,21 @@ interface PermissionStore {
long DYNAMIC_ALL_BITS = -1;
/**
- * Loads the permission entries for the given principal and path. if the
given {@code entries} is {@code null}, it
- * will be created automatically if needed. If a {@code entries} is given,
it will reuse it and the same object is
- * returned. If no entries can be found for the given principal or path,
{@code null} is returned.
+ * Loads the permission entries for the given principal and path. If no
+ * entries can be found for the given principal or path, {@code null} is
returned.
*
- * @param entries the permission entries or {@code null}
* @param principalName name of the principal
* @param path access controlled path.
* @return the given {@code entries}, a new collection or {@code null}
*/
@CheckForNull
- Collection<PermissionEntry> load(@Nullable Collection<PermissionEntry>
entries, @Nonnull String principalName, @Nonnull String path);
+ Collection<PermissionEntry> load(@Nonnull String principalName, @Nonnull
String path);
@Nonnull
PrincipalPermissionEntries load(@Nonnull String principalName);
- long getNumEntries(@Nonnull String principalName, long max);
+ @Nonnull
+ NumEntries getNumEntries(@Nonnull String principalName, long max);
void flush(@Nonnull Root root);
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java?rev=1830843&r1=1830842&r2=1830843&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java
Thu May 3 16:51:10 2018
@@ -92,7 +92,7 @@ final class PermissionStoreEditor implem
new AcEntry(ace, accessControlledPath, index, isAllow,
privilegeBits, restrictions);
List<AcEntry> list = entries.get(entry.principalName);
if (list == null) {
- list = new ArrayList<AcEntry>();
+ list = new ArrayList<>();
entries.put(entry.principalName, list);
}
list.add(entry);
@@ -117,6 +117,7 @@ final class PermissionStoreEditor implem
for (String principalName : entries.keySet()) {
if (permissionRoot.hasChildNode(principalName)) {
NodeBuilder principalRoot =
permissionRoot.getChildNode(principalName);
+ boolean removed = false;
// find the ACL node that for this path and principal
NodeBuilder parent = principalRoot.getChildNode(nodeName);
@@ -139,11 +140,13 @@ final class PermissionStoreEditor implem
newParent.setChildNode(childName,
child.getNodeState());
}
}
+
if (newParent != null) {
- // replace the 'parent', which needs to be removed
+ // replace the 'parent', which got removed
principalRoot.setChildNode(nodeName,
newParent.getNodeState());
+ removed = true;
} else {
- parent.remove();
+ removed = parent.remove();
}
} else {
// check if any of the child nodes match
@@ -153,10 +156,13 @@ final class PermissionStoreEditor implem
}
NodeBuilder child = parent.getChildNode(childName);
if (PermissionUtil.checkACLPath(child,
accessControlledPath)) {
- child.remove();
+ removed = child.remove();
}
}
}
+ if (removed) {
+ updateNumEntries(principalName, principalRoot, -1);
+ }
} else {
log.error("Unable to remove permission entry {}: Principal
root missing.", this);
}
@@ -210,6 +216,10 @@ final class PermissionStoreEditor implem
parent.setProperty(REP_ACCESS_CONTROLLED_PATH,
accessControlledPath);
}
updateEntries(parent, entry.getValue());
+
+ if (parent.isNew()) {
+ updateNumEntries(principalName, principalRoot, +1);
+ }
}
}
@@ -225,6 +235,21 @@ final class PermissionStoreEditor implem
}
}
+ private static void updateNumEntries(@Nonnull String principalName,
@Nonnull NodeBuilder principalRoot, int cnt) {
+ PropertyState ps = principalRoot.getProperty(REP_NUM_PERMISSIONS);
+ long numEntries = ((ps == null) ? 0 : ps.getValue(Type.LONG)) + cnt;
+ if (ps == null && !principalRoot.isNew()) {
+ // existing principal root that doesn't have the rep:numEntries set
+ return;
+ } else if (numEntries < 0) {
+ // numEntries unexpectedly turned negative
+ log.error("NumEntries counter for principal '"+principalName+"'
turned negative -> removing 'rep:numPermissions' property.");
+ principalRoot.removeProperty(REP_NUM_PERMISSIONS);
+ } else {
+ principalRoot.setProperty(REP_NUM_PERMISSIONS, numEntries,
Type.LONG);
+ }
+ }
+
private final class JcrAllAcEntry extends AcEntry {
private JcrAllAcEntry(@Nonnull NodeState node,
@@ -251,7 +276,7 @@ final class PermissionStoreEditor implem
private final int index;
private int hashCode = -1;
- private AcEntry(@Nonnull NodeState node, @Nonnull String
accessControlledPath, int index,
+ AcEntry(@Nonnull NodeState node, @Nonnull String accessControlledPath,
int index,
boolean isAllow, @Nonnull PrivilegeBits privilegeBits,
@Nonnull Set<Restriction> restrictions) {
this.accessControlledPath = accessControlledPath;
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java?rev=1830843&r1=1830842&r2=1830843&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java
Thu May 3 16:51:10 2018
@@ -20,21 +20,19 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;
-
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
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.plugins.tree.TreeUtil;
import
org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
import
org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
-import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -52,7 +50,7 @@ class PermissionStoreImpl implements Per
private final RestrictionProvider restrictionProvider;
- private final Map<String, Tree> principalTreeMap = new HashMap<String,
Tree>();
+ private final Map<String, Tree> principalTreeMap = new HashMap<>();
private Tree permissionsTree;
private PrivilegeBits allBits;
@@ -75,21 +73,24 @@ class PermissionStoreImpl implements Per
}
//----------------------------------------------------< PermissionStore
>---
- @Override
@CheckForNull
- public Collection<PermissionEntry> load(@Nullable
Collection<PermissionEntry> entries, @Nonnull String principalName, @Nonnull
String path) {
+ @Override
+ public Collection<PermissionEntry> load(@Nonnull String principalName,
@Nonnull String path) {
Tree principalRoot = getPrincipalRoot(principalName);
+ Collection<PermissionEntry> entries = null;
if (principalRoot != null) {
String name = PermissionUtil.getEntryName(path);
if (principalRoot.hasChild(name)) {
Tree child = principalRoot.getChild(name);
if (PermissionUtil.checkACLPath(child, path)) {
- entries = loadPermissionEntries(path, entries, child);
+ entries = loadPermissionEntries(path, child);
} else {
- // check for child node
+ // check for child node : there may at most be one child
for
+ // the given path.
for (Tree node : child.getChildren()) {
if (PermissionUtil.checkACLPath(node, path)) {
- entries = loadPermissionEntries(path, entries,
node);
+ entries = loadPermissionEntries(path, node);
+ break;
}
}
}
@@ -98,11 +99,21 @@ class PermissionStoreImpl implements Per
return entries == null || entries.isEmpty() ? null : entries;
}
+ @Nonnull
@Override
- public long getNumEntries(@Nonnull String principalName, long max) {
- // we ignore the hash-collisions here
+ public NumEntries getNumEntries(@Nonnull String principalName, long max) {
Tree tree = getPrincipalRoot(principalName);
- return tree == null ? 0 : tree.getChildrenCount(max);
+ if (tree == null) {
+ return NumEntries.ZERO;
+ } else {
+ // if rep:numPermissions is present it contains the exact number of
+ // access controlled nodes for the given principal name.
+ // if this property is missing (backward compat) we use the old
+ // mechanism and use child-cnt with a max value to get a rough idea
+ // about the magnitude (note: this approximation ignores the
hash-collisions)
+ long l = TreeUtil.getLong(tree, REP_NUM_PERMISSIONS, -1);
+ return (l >= 0) ? NumEntries.valueOf(l, true) :
NumEntries.valueOf(tree.getChildrenCount(max), false);
+ }
}
@Override
@@ -113,7 +124,7 @@ class PermissionStoreImpl implements Per
Tree principalRoot = getPrincipalRoot(principalName);
if (principalRoot != null) {
for (Tree entryTree : principalRoot.getChildren()) {
- loadPermissionEntries(entryTree, ret.getEntries());
+ loadPermissionEntries(entryTree, ret);
}
}
ret.setFullyLoaded(true);
@@ -140,17 +151,17 @@ class PermissionStoreImpl implements Per
}
private void loadPermissionEntries(@Nonnull Tree tree,
- @Nonnull Map<String,
Collection<PermissionEntry>> pathEntryMap) {
+ @Nonnull PrincipalPermissionEntries
principalPermissionEntries) {
String path = TreeUtil.getString(tree,
PermissionConstants.REP_ACCESS_CONTROLLED_PATH);
if (path != null) {
- Collection<PermissionEntry> entries = pathEntryMap.get(path);
+ Collection<PermissionEntry> entries =
principalPermissionEntries.getEntriesByPath(path);
if (entries == null) {
- entries = new TreeSet<PermissionEntry>();
- pathEntryMap.put(path, entries);
+ entries = new TreeSet<>();
+ principalPermissionEntries.putEntriesByPath(path, entries);
}
for (Tree child : tree.getChildren()) {
if (child.getName().charAt(0) == 'c') {
- loadPermissionEntries(child, pathEntryMap);
+ loadPermissionEntries(child, principalPermissionEntries);
} else {
entries.add(createPermissionEntry(path, child));
}
@@ -160,15 +171,11 @@ class PermissionStoreImpl implements Per
}
}
- @CheckForNull
private Collection<PermissionEntry> loadPermissionEntries(@Nonnull String
path,
- @Nullable
Collection<PermissionEntry> ret,
- @Nonnull Tree
tree) {
+ @Nonnull Tree tree) {
+ Collection<PermissionEntry> ret = new TreeSet<>();
for (Tree ace : tree.getChildren()) {
if (ace.getName().charAt(0) != 'c') {
- if (ret == null) {
- ret = new TreeSet<PermissionEntry>();
- }
ret.add(createPermissionEntry(path, ace));
}
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PrincipalPermissionEntries.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PrincipalPermissionEntries.java?rev=1830843&r1=1830842&r2=1830843&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PrincipalPermissionEntries.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PrincipalPermissionEntries.java
Thu May 3 16:51:10 2018
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.oak.securi
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
@@ -26,6 +27,8 @@ import javax.annotation.Nonnull;
*/
class PrincipalPermissionEntries {
+ private final long expectedSize;
+
/**
* indicating if all entries were loaded.
*/
@@ -34,9 +37,14 @@ class PrincipalPermissionEntries {
/**
* map of permission entries, accessed by path
*/
- private Map<String, Collection<PermissionEntry>> entries = new
HashMap<String, Collection<PermissionEntry>>();
+ private Map<String, Collection<PermissionEntry>> entries = new HashMap<>();
PrincipalPermissionEntries() {
+ this(Long.MAX_VALUE);
+ }
+
+ PrincipalPermissionEntries(long expectedSize) {
+ this.expectedSize = expectedSize;
}
long getSize() {
@@ -55,4 +63,21 @@ class PrincipalPermissionEntries {
Map<String, Collection<PermissionEntry>> getEntries() {
return entries;
}
+
+ @CheckForNull
+ Collection<PermissionEntry> getEntriesByPath(@Nonnull String path) {
+ return entries.get(path);
+ }
+
+ void putEntriesByPath(@Nonnull String path, @Nonnull
Collection<PermissionEntry> pathEntries) {
+ entries.put(path, pathEntries);
+ if (entries.size() >= expectedSize) {
+ setFullyLoaded(true);
+ }
+ }
+
+ void putAllEntries(@Nonnull Map<String, Collection<PermissionEntry>>
allEntries) {
+ entries.putAll(allEntries);
+ setFullyLoaded(true);
+ }
}
\ No newline at end of file
Added:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/EmptyPermissionCacheTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/EmptyPermissionCacheTest.java?rev=1830843&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/EmptyPermissionCacheTest.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/EmptyPermissionCacheTest.java
Thu May 3 16:51:10 2018
@@ -0,0 +1,50 @@
+/*
+ * 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.security.authorization.permission;
+
+import com.google.common.collect.ImmutableSet;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+public class EmptyPermissionCacheTest {
+
+ private PermissionCache empty;
+
+ @Before
+ public void before() {
+ PermissionCacheBuilder builder = new
PermissionCacheBuilder(Mockito.mock(PermissionStore.class));
+ builder.init(ImmutableSet.of(), Long.MAX_VALUE);
+ empty = builder.build();
+ }
+
+ @Test
+ public void testGetEntriesByPath() {
+ assertTrue(empty.getEntries("/path").isEmpty());
+ }
+
+ @Test
+ public void testGetEntriesByTree() {
+ Tree tree = Mockito.mock(Tree.class);
+ when(tree.getPath()).thenReturn("/path");
+ assertTrue(empty.getEntries(tree).isEmpty());
+ }
+}
\ No newline at end of file
Propchange:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/EmptyPermissionCacheTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/MountPermissionStoreTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/MountPermissionStoreTest.java?rev=1830843&r1=1830842&r2=1830843&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/MountPermissionStoreTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/MountPermissionStoreTest.java
Thu May 3 16:51:10 2018
@@ -46,6 +46,8 @@ import static org.junit.Assert.assertEqu
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;
public class MountPermissionStoreTest extends AbstractSecurityTest {
@@ -114,14 +116,14 @@ public class MountPermissionStoreTest ex
@Test
public void testLoadByAccessControlledPath() {
- Collection<PermissionEntry> entries = permissionStore.load(null,
EveryonePrincipal.NAME, CONTENT_PATH);
+ Collection<PermissionEntry> entries =
permissionStore.load(EveryonePrincipal.NAME, CONTENT_PATH);
assertNotNull(entries);
assertEquals(1, entries.size());
}
@Test
public void testLoadByNonAccessControlledPath() {
- Collection<PermissionEntry> entries = permissionStore.load(null,
EveryonePrincipal.NAME, TEST_PATH);
+ Collection<PermissionEntry> entries =
permissionStore.load(EveryonePrincipal.NAME, TEST_PATH);
assertNull(entries);
}
@@ -143,22 +145,36 @@ public class MountPermissionStoreTest ex
@Test
public void testGetNumEntries() {
- assertEquals(2, permissionStore.getNumEntries(EveryonePrincipal.NAME,
10));
+ assertEquals(2, permissionStore.getNumEntries(EveryonePrincipal.NAME,
10).size);
}
+ @Test
+ public void testGetNumEntriesMaxReachedExact() throws Exception {
+ PermissionStoreImpl mock = insertMockStore();
+ when(mock.getNumEntries(anyString(),
anyLong())).thenReturn(NumEntries.valueOf(2, true));
+
+ NumEntries ne = permissionStore.getNumEntries(EveryonePrincipal.NAME,
10);
+ assertEquals(NumEntries.valueOf(4, true), ne);
+
+ ne = permissionStore.getNumEntries(EveryonePrincipal.NAME, 2);
+ assertEquals(NumEntries.valueOf(4, true), ne);
+ }
@Test
- public void testGetNumEntriesMaxReached() throws Exception {
+ public void testGetNumEntriesMaxReachedNotExact() throws Exception {
PermissionStoreImpl mock = insertMockStore();
- when(mock.getNumEntries(EveryonePrincipal.NAME,
Long.valueOf(10))).thenReturn(Long.valueOf(2));
+ when(mock.getNumEntries(anyString(),
anyLong())).thenReturn(NumEntries.valueOf(2, false));
+
+ NumEntries ne = permissionStore.getNumEntries(EveryonePrincipal.NAME,
10);
+ assertEquals(NumEntries.valueOf(4, false), ne);
- assertEquals(4, permissionStore.getNumEntries(EveryonePrincipal.NAME,
10));
- assertEquals(2, permissionStore.getNumEntries(EveryonePrincipal.NAME,
2));
+ ne = permissionStore.getNumEntries(EveryonePrincipal.NAME, 2);
+ assertEquals(NumEntries.valueOf(2, false), ne);
}
@Test
public void testGetNumEntriesUnknownPrincipalName() {
- assertEquals(0, permissionStore.getNumEntries("unknown", 10));
+ assertEquals(0, permissionStore.getNumEntries("unknown", 10).size);
}
@Test
@@ -176,7 +192,7 @@ public class MountPermissionStoreTest ex
PermissionStoreImpl mock = Mockito.mock(PermissionStoreImpl.class);
List<PermissionStoreImpl> stores = (List<PermissionStoreImpl>)
f.get(permissionStore);
- stores.add(mock);
+ stores.add(0, mock);
return mock;
}
}
\ No newline at end of file
Added:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/NumEntriesTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/NumEntriesTest.java?rev=1830843&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/NumEntriesTest.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/NumEntriesTest.java
Thu May 3 16:51:10 2018
@@ -0,0 +1,85 @@
+/*
+ * 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.security.authorization.permission;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+public class NumEntriesTest {
+
+ @Test
+ public void testZero() {
+ assertTrue(NumEntries.ZERO.isExact);
+ assertEquals(0, NumEntries.ZERO.size);
+ }
+
+ @Test
+ public void testValueOfExactZero() {
+ assertSame(NumEntries.ZERO, NumEntries.valueOf(0, true));
+ }
+
+ @Test
+ public void testValueOfNotExactZero() {
+ NumEntries ne = NumEntries.valueOf(0, false);
+ assertSame(NumEntries.ZERO, ne);
+ }
+
+ @Test
+ public void testValueOfExact() {
+ NumEntries ne = NumEntries.valueOf(25, true);
+ assertTrue(ne.isExact);
+ assertEquals(25, ne.size);
+ }
+
+ @Test
+ public void testValueOfNotExact() {
+ NumEntries ne = NumEntries.valueOf(25, false);
+ assertFalse(ne.isExact);
+ assertEquals(25, ne.size);
+ }
+
+ @Test
+ public void testEquals() {
+ assertEquals(NumEntries.ZERO, NumEntries.ZERO);
+ NumEntries ne1True = NumEntries.valueOf(1, true);
+ NumEntries ne2True = NumEntries.valueOf(2, true);
+ NumEntries ne1False = NumEntries.valueOf(1, false);
+
+ assertEquals(ne1True, ne1True);
+ assertNotEquals(ne1False, ne1True);
+ assertNotEquals(ne2True, ne1True);
+
+ assertFalse(ne1True.equals(null));
+ assertFalse(ne1True.equals(new Object()));
+ }
+
+ @Test
+ public void testHashCode() {
+ assertEquals(NumEntries.ZERO.hashCode(), NumEntries.ZERO.hashCode());
+ NumEntries ne1True = NumEntries.valueOf(1, true);
+ NumEntries ne1False = NumEntries.valueOf(1, false);
+
+ assertEquals(ne1True.hashCode(), ne1True.hashCode());
+ assertNotEquals(ne1False.hashCode(), ne1True.hashCode());
+ }
+}
\ No newline at end of file
Propchange:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/NumEntriesTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCacheBuilderTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCacheBuilderTest.java?rev=1830843&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCacheBuilderTest.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCacheBuilderTest.java
Thu May 3 16:51:10 2018
@@ -0,0 +1,146 @@
+/*
+ * 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.security.authorization.permission;
+
+import java.util.Set;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import
org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionPattern;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.when;
+
+public class PermissionCacheBuilderTest {
+
+ private static final String EMPTY_CLASS_NAME =
"org.apache.jackrabbit.oak.security.authorization.permission.PermissionCacheBuilder$EmptyCache";
+ private static final String SIMPLE_CLASS_NAME =
"org.apache.jackrabbit.oak.security.authorization.permission.PermissionCacheBuilder$PathEntryMapCache";
+ private static final String DEFAULT_CLASS_NAME =
"org.apache.jackrabbit.oak.security.authorization.permission.PermissionCacheBuilder$DefaultPermissionCache";
+
+ private PermissionStore store;
+ private PermissionCacheBuilder permissionCacheBuilder;
+
+ @Before
+ public void before() {
+ store = Mockito.mock(PermissionStore.class);
+ permissionCacheBuilder = new PermissionCacheBuilder(store);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testBuildBeforeInitialized() {
+ permissionCacheBuilder.build();
+ }
+
+ @Test
+ public void testBuildForEmptyPrincipals() {
+ assertTrue(permissionCacheBuilder.init(ImmutableSet.of(),
Long.MAX_VALUE));
+ permissionCacheBuilder.init(ImmutableSet.of(), Long.MAX_VALUE);
+ PermissionCache cache = permissionCacheBuilder.build();
+ assertEquals(EMPTY_CLASS_NAME, cache.getClass().getName());
+ }
+
+ @Test
+ public void testBuildNoExistingEntries() throws Exception {
+ when(store.getNumEntries(anyString(),
anyLong())).thenReturn(NumEntries.ZERO);
+ when(store.load(anyString())).thenReturn(new
PrincipalPermissionEntries(0));
+
+ Set<String> principalNames = Sets.newHashSet("noEntries",
"noEntries2", "noEntries3");
+
+ assertTrue(permissionCacheBuilder.init(principalNames,
Long.MAX_VALUE));
+ PermissionCache cache = permissionCacheBuilder.build();
+ assertEquals(EMPTY_CLASS_NAME, cache.getClass().getName());
+ }
+
+ @Test
+ public void testBuildFewEntriesSamePath() throws Exception {
+ PrincipalPermissionEntries ppeA = new PrincipalPermissionEntries(1);
+ ppeA.putEntriesByPath("/path", ImmutableSet.of(new
PermissionEntry("/path", false, 0,
PrivilegeBits.BUILT_IN.get(PrivilegeBits.REP_READ_NODES),
RestrictionPattern.EMPTY)));
+
+ PrincipalPermissionEntries ppeB = new PrincipalPermissionEntries(1);
+ ppeB.putEntriesByPath("/path", ImmutableSet.of(new
PermissionEntry("/path", false, 1,
PrivilegeBits.BUILT_IN.get(PrivilegeBits.REP_READ_NODES),
RestrictionPattern.EMPTY)));
+
+ when(store.load("a")).thenReturn(ppeA);
+ when(store.load("b")).thenReturn(ppeB);
+ when(store.getNumEntries(anyString(),
anyLong())).thenReturn(NumEntries.valueOf(1, true));
+
+ Set<String> principalNames = Sets.newHashSet("a", "b");
+ assertFalse(permissionCacheBuilder.init(principalNames,
Long.MAX_VALUE));
+
+ PermissionCache cache = permissionCacheBuilder.build();
+ assertEquals(SIMPLE_CLASS_NAME, cache.getClass().getName());
+ }
+
+ @Test
+ public void testBuildFewEntriesDifferentPaths() throws Exception {
+ PrincipalPermissionEntries ppeA = new PrincipalPermissionEntries(1);
+ ppeA.putEntriesByPath("/path", ImmutableSet.of(new
PermissionEntry("/path", false, 0,
PrivilegeBits.BUILT_IN.get(PrivilegeBits.REP_READ_NODES),
RestrictionPattern.EMPTY)));
+
+ PrincipalPermissionEntries ppeB = new PrincipalPermissionEntries(1);
+ ppeB.putEntriesByPath("/path", ImmutableSet.of(new
PermissionEntry("/path", false, 1,
PrivilegeBits.BUILT_IN.get(PrivilegeBits.REP_READ_NODES),
RestrictionPattern.EMPTY)));
+
+ when(store.load("a")).thenReturn(ppeA);
+ when(store.load("b")).thenReturn(ppeB);
+ when(store.getNumEntries(anyString(),
anyLong())).thenReturn(NumEntries.valueOf(1, true));
+
+ Set<String> principalNames = Sets.newHashSet("a", "b");
+ assertFalse(permissionCacheBuilder.init(principalNames,
Long.MAX_VALUE));
+
+ PermissionCache cache = permissionCacheBuilder.build();
+ assertEquals(SIMPLE_CLASS_NAME, cache.getClass().getName());
+ }
+
+ @Test
+ public void testNoEntriesNonExactCnt() throws Exception {
+ when(store.load("a")).thenReturn(new PrincipalPermissionEntries());
+ when(store.load("b")).thenReturn(new PrincipalPermissionEntries());
+ when(store.getNumEntries(anyString(),
anyLong())).thenReturn(NumEntries.valueOf(1, false));
+
+ Set<String> principalNames = Sets.newHashSet("a", "b");
+ assertFalse(permissionCacheBuilder.init(principalNames,
Long.MAX_VALUE));
+
+ PermissionCache cache = permissionCacheBuilder.build();
+ assertEquals(EMPTY_CLASS_NAME, cache.getClass().getName());
+ }
+
+ @Test
+ public void testBuildMaxEntriesReached() throws Exception {
+ PrincipalPermissionEntries ppeA = new PrincipalPermissionEntries(1);
+ ppeA.putEntriesByPath("/path1", ImmutableSet.of(new
PermissionEntry("/path1", false, 0,
PrivilegeBits.BUILT_IN.get(PrivilegeBits.REP_READ_NODES),
RestrictionPattern.EMPTY)));
+
+ PrincipalPermissionEntries ppeB = new PrincipalPermissionEntries(1);
+ ppeA.putEntriesByPath("/path2", ImmutableSet.of(new
PermissionEntry("/path2", false, 0,
PrivilegeBits.BUILT_IN.get(PrivilegeBits.REP_READ_NODES),
RestrictionPattern.EMPTY)));
+
+ when(store.load("a")).thenReturn(ppeA);
+ when(store.load("b")).thenReturn(ppeB);
+ when(store.getNumEntries(anyString(),
anyLong())).thenReturn(NumEntries.valueOf(1, true));
+
+ Set<String> principalNames = Sets.newHashSet("a", "b");
+ long maxSize = 1;
+ assertFalse(permissionCacheBuilder.init(principalNames, maxSize));
+
+ PermissionCache cache = permissionCacheBuilder.build();
+ assertEquals(DEFAULT_CLASS_NAME, cache.getClass().getName());
+ }
+}
\ No newline at end of file
Propchange:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionCacheBuilderTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryCacheTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryCacheTest.java?rev=1830843&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryCacheTest.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryCacheTest.java
Thu May 3 16:51:10 2018
@@ -0,0 +1,218 @@
+/*
+ * 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.security.authorization.permission;
+
+import java.lang.reflect.Field;
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeSet;
+import javax.annotation.Nonnull;
+
+import com.google.common.collect.Sets;
+import
org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionPattern;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+public class PermissionEntryCacheTest {
+
+ private PermissionEntryCache cache = new PermissionEntryCache();
+
+ private PermissionEntry permissionEntry;
+ private PrincipalPermissionEntries ppe;
+ private PermissionStore store;
+
+ @Before
+ public void before() {
+ permissionEntry = new PermissionEntry("/path", true, 0,
PrivilegeBits.BUILT_IN.get(PrivilegeBits.JCR_READ), RestrictionPattern.EMPTY);
+ ppe = new PrincipalPermissionEntries();
+ ppe.putEntriesByPath("/path", Sets.newHashSet(permissionEntry));
+
+ store = Mockito.mock(PermissionStore.class);
+
+ }
+
+ private PrincipalPermissionEntries getPrincipalPermissionEntries(boolean
fullyLoaded) {
+ ppe.setFullyLoaded(fullyLoaded);
+ return ppe;
+ }
+
+ @Test
+ public void testMissingInit() throws Exception {
+ Map<String, PrincipalPermissionEntries> entries =
inspectEntries(cache);
+ assertNotNull(entries);
+ assertTrue(entries.isEmpty());
+ }
+
+ @Test
+ public void testInit() throws Exception {
+ cache.init("a", 5);
+
+ PrincipalPermissionEntries entries = inspectEntries(cache, "a");
+ assertNotNull(entries);
+ assertFalse(entries.isFullyLoaded());
+ assertEquals(0, entries.getSize());
+
+ entries = inspectEntries(cache, "notInitialized");
+ assertNull(entries);
+ }
+
+ @Test
+ public void testLoadMissingInit() throws Exception {
+ PrincipalPermissionEntries ppeA = getPrincipalPermissionEntries(true);
+
+ when(store.load("a")).thenReturn(ppeA);
+
+ Collection<PermissionEntry> result = new TreeSet();
+ cache.load(store, result, "a", "/path");
+
+ assertTrue(result.isEmpty());
+ }
+
+ @Test
+ public void testLoadNotComplete() throws Exception {
+ cache.init("a", Long.MAX_VALUE);
+
+ Collection<PermissionEntry> entries = Sets.newHashSet(permissionEntry);
+ when(store.load("a", "/path")).thenReturn(entries);
+
+ Collection<PermissionEntry> result = Sets.newHashSet();
+ cache.load(store, result, "a", "/path");
+
+ assertEquals(entries, result);
+
+ PrincipalPermissionEntries inspectedEntries = inspectEntries(cache,
"a");
+ assertFalse(inspectedEntries.isFullyLoaded());
+
+ // requesting the entries again must NOT hit the store
+ when(store.load("a", "/path")).thenThrow(IllegalStateException.class);
+
+ result.clear();
+ cache.load(store, result, "a", "/path");
+
+ assertEquals(entries, result);
+ }
+
+ @Test
+ public void testLoadCompleted() throws Exception {
+ cache.init("a", 1);
+
+ Collection<PermissionEntry> entries = Sets.newHashSet(permissionEntry);
+ when(store.load("a", "/path")).thenReturn(entries);
+
+ Collection<PermissionEntry> result = Sets.newHashSet();
+ cache.load(store, result, "a", "/path");
+
+ assertEquals(entries, result);
+
+ PrincipalPermissionEntries inspectedEntries = inspectEntries(cache,
"a");
+ assertTrue(inspectedEntries.isFullyLoaded());
+
+ // requesting the entries again must NOT hit the store
+ when(store.load("a", "/path")).thenThrow(IllegalStateException.class);
+
+ result.clear();
+ cache.load(store, result, "a", "/path");
+
+ assertEquals(entries, result);
+ }
+
+ @Test
+ public void testLoadNonExistingNotComplete() throws Exception {
+ cache.init("a", Long.MAX_VALUE);
+
+ when(store.load("a", "/path")).thenReturn(null);
+
+ Collection<PermissionEntry> result = Sets.newHashSet();
+ cache.load(store, result, "a", "/path");
+
+ assertTrue(result.isEmpty());
+
+ PrincipalPermissionEntries inspectedEntries = inspectEntries(cache,
"a");
+ assertFalse(inspectedEntries.isFullyLoaded());
+
+ // requesting the entries again must NOT hit the store
+ when(store.load("a", "/path")).thenThrow(IllegalStateException.class);
+
+ result.clear();
+ cache.load(store, result, "a", "/path");
+
+ assertTrue(result.isEmpty());
+ }
+
+ @Test
+ public void testLoadNonExistingCompleted() throws Exception {
+ cache.init("a", 0);
+ when(store.load("a", "/path")).thenReturn(null);
+
+ Collection<PermissionEntry> result = Sets.newHashSet();
+ cache.load(store, result, "a", "/path");
+
+ assertTrue(result.isEmpty());
+
+ PrincipalPermissionEntries inspectedEntries = inspectEntries(cache,
"a");
+ assertTrue(inspectedEntries.isFullyLoaded());
+
+ // requesting the entries again must NOT hit the store
+ when(store.load("a", "/path")).thenThrow(IllegalStateException.class);
+
+ result.clear();
+ cache.load(store, result, "a", "/path");
+
+ assertTrue(result.isEmpty());
+ }
+
+
+ @Test
+ public void testGetFullyLoadedEntries() throws Exception {
+ PrincipalPermissionEntries ppeA = getPrincipalPermissionEntries(true);
+
+ when(store.load("a")).thenReturn(ppeA);
+
+ PrincipalPermissionEntries entries =
cache.getFullyLoadedEntries(store, "a");
+ assertSame(ppeA, entries);
+
+ PrincipalPermissionEntries inspectedEntries = inspectEntries(cache,
"a");
+ assertSame(ppeA, inspectedEntries);
+
+ // requesting the entries again must NOT hit the store
+ when(store.load("a")).thenThrow(IllegalStateException.class);
+ entries = cache.getFullyLoadedEntries(store, "a");
+ assertSame(ppeA, entries);
+ }
+
+ private static PrincipalPermissionEntries inspectEntries(@Nonnull
PermissionEntryCache cache, @Nonnull String principalName) throws Exception {
+ Map<String, PrincipalPermissionEntries> entries =
inspectEntries(cache);
+ return entries.get(principalName);
+ }
+
+ private static Map<String, PrincipalPermissionEntries>
inspectEntries(@Nonnull PermissionEntryCache cache) throws Exception {
+ Field f = PermissionEntryCache.class.getDeclaredField("entries");
+ f.setAccessible(true);
+
+ return (Map<String, PrincipalPermissionEntries>) f.get(cache);
+ }
+}
\ No newline at end of file
Propchange:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryCacheTest.java
------------------------------------------------------------------------------
svn:eol-style = native