diff --git a/repository/src/main/java/org/alfresco/repo/security/permissions/PermissionCheckCollection.java b/repository/src/main/java/org/alfresco/repo/security/permissions/PermissionCheckCollection.java
index 24b300b8e2..49f2fd840f 100644
--- a/repository/src/main/java/org/alfresco/repo/security/permissions/PermissionCheckCollection.java
+++ b/repository/src/main/java/org/alfresco/repo/security/permissions/PermissionCheckCollection.java
@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
- * Copyright (C) 2005 - 2016 Alfresco Software Limited
+ * Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -23,133 +23,127 @@
* along with Alfresco. If not, see .
* #L%
*/
-package org.alfresco.repo.security.permissions;
-
-import java.util.Collection;
-
-import org.springframework.aop.IntroductionAdvisor;
-import org.springframework.aop.framework.ProxyFactory;
-import org.springframework.aop.support.DefaultIntroductionAdvisor;
-import org.springframework.aop.support.DelegatingIntroductionInterceptor;
-
-/**
- * Interface for collection-based results that describe permission filtering
- * behaviour around cut-off limits.
- *
- * @author Derek Hulley
- * @since 4.0
- */
-public interface PermissionCheckCollection
-{
- /**
- * Get the desired number of results. Permission checks can stop once the number of
- * return objects reaches this number.
- *
- * @return the number of results desired
- */
- int getTargetResultCount();
-
- /**
- * Get the maximum time for permission checks to execute before cutting the results off.
- *
Zero: Ignore this value.
- *
- * @return the time allowed for permission checks before cutoff
- */
- long getCutOffAfterTimeMs();
-
- /**
- * Get the maximum number of permission checks to perform before cutting the results off
- *
- * @return the maximum number of permission checks before cutoff
- */
- int getCutOffAfterCount();
-
- /**
- * Helper 'introduction' to allow simple addition of the {@link PermissionCheckCollection} interface to
- * existing collections.
- *
- * @param the type of the Collection
in use
- *
- * @author Derek Hulley
- * @since 4.0
- */
- @SuppressWarnings("serial")
- public static class PermissionCheckCollectionMixin extends DelegatingIntroductionInterceptor implements PermissionCheckCollection
- {
- private final int targetResultCount;
- private final long cutOffAfterTimeMs;
- private final int cutOffAfterCount;
-
- private PermissionCheckCollectionMixin(int targetResultCount, long cutOffAfterTimeMs, int cutOffAfterCount)
- {
- super();
- this.targetResultCount = targetResultCount;
- this.cutOffAfterTimeMs = cutOffAfterTimeMs;
- this.cutOffAfterCount = cutOffAfterCount;
- if (cutOffAfterTimeMs <= 0)
- {
- cutOffAfterTimeMs = 0;
- }
- if (cutOffAfterCount <= 0)
- {
- cutOffAfterCount = 0;
- }
- }
-
- @Override
- public int getTargetResultCount()
- {
- return targetResultCount;
- }
-
- @Override
- public long getCutOffAfterTimeMs()
- {
- return cutOffAfterTimeMs;
- }
-
- @Override
- public int getCutOffAfterCount()
- {
- return cutOffAfterCount;
- }
-
- /**
- * Helper method to create a {@link PermissionCheckCollection} from an existing Collection
- *
- * @param the type of the Collection
- * @param collection the Collection
to proxy
- * @param targetResultCount the desired number of results or default to the collection size
- * @param cutOffAfterTimeMs the number of milliseconds to wait before cut-off or zero to use the system default
- * time-based cut-off.
- * @param cutOffAfterCount the number of permission checks to process before cut-off or zero to use the system default
- * count-based cut-off.
- * @return a Collection
of the same type but including the
- * {@link PermissionCheckCollection} interface
- */
- @SuppressWarnings("unchecked")
- public static final Collection create(
- Collection collection,
- int targetResultCount, long cutOffAfterTimeMs, int cutOffAfterCount)
- {
- if (targetResultCount <= 0)
- {
- targetResultCount = collection.size();
- }
- // Create the mixin
- DelegatingIntroductionInterceptor mixin = new PermissionCheckCollectionMixin(
- targetResultCount,
- cutOffAfterTimeMs,
- cutOffAfterCount);
- // Create the advisor
- IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(mixin, PermissionCheckCollection.class);
- // Proxy
- ProxyFactory pf = new ProxyFactory(collection);
- pf.addAdvisor(advisor);
- Object proxiedObject = pf.getProxy();
-
- // Done
- return (Collection) proxiedObject;
- }
- }
-}
+package org.alfresco.repo.security.permissions;
+
+import java.util.Collection;
+
+import org.springframework.aop.IntroductionAdvisor;
+import org.springframework.aop.support.DefaultIntroductionAdvisor;
+import org.springframework.aop.support.DelegatingIntroductionInterceptor;
+
+/**
+ * Interface for collection-based results that describe permission filtering behaviour around cut-off limits.
+ *
+ * @author Derek Hulley
+ * @since 4.0
+ */
+public interface PermissionCheckCollection
+{
+ /**
+ * Get the desired number of results. Permission checks can stop once the number of return objects reaches this number.
+ *
+ * @return the number of results desired
+ */
+ int getTargetResultCount();
+
+ /**
+ * Get the maximum time for permission checks to execute before cutting the results off.
+ * Zero: Ignore this value.
+ *
+ * @return the time allowed for permission checks before cutoff
+ */
+ long getCutOffAfterTimeMs();
+
+ /**
+ * Get the maximum number of permission checks to perform before cutting the results off
+ *
+ * @return the maximum number of permission checks before cutoff
+ */
+ int getCutOffAfterCount();
+
+ /**
+ * Helper 'introduction' to allow simple addition of the {@link PermissionCheckCollection} interface to existing collections.
+ *
+ * @param
+ * the type of the Collection
in use
+ *
+ * @author Derek Hulley
+ * @since 4.0
+ */
+ @SuppressWarnings("serial")
+ class PermissionCheckCollectionMixin extends DelegatingIntroductionInterceptor implements PermissionCheckCollection
+ {
+ private final int targetResultCount;
+ private final long cutOffAfterTimeMs;
+ private final int cutOffAfterCount;
+
+ private PermissionCheckCollectionMixin(int targetResultCount, long cutOffAfterTimeMs, int cutOffAfterCount)
+ {
+ super();
+ this.targetResultCount = targetResultCount;
+ this.cutOffAfterTimeMs = cutOffAfterTimeMs;
+ this.cutOffAfterCount = cutOffAfterCount;
+ if (cutOffAfterTimeMs <= 0)
+ {
+ cutOffAfterTimeMs = 0;
+ }
+ if (cutOffAfterCount <= 0)
+ {
+ cutOffAfterCount = 0;
+ }
+ }
+
+ @Override
+ public int getTargetResultCount()
+ {
+ return targetResultCount;
+ }
+
+ @Override
+ public long getCutOffAfterTimeMs()
+ {
+ return cutOffAfterTimeMs;
+ }
+
+ @Override
+ public int getCutOffAfterCount()
+ {
+ return cutOffAfterCount;
+ }
+
+ /**
+ * Helper method to create a {@link PermissionCheckCollection} from an existing Collection
+ *
+ * @param
+ * the type of the Collection
+ * @param collection
+ * the Collection
to proxy
+ * @param targetResultCount
+ * the desired number of results or default to the collection size
+ * @param cutOffAfterTimeMs
+ * the number of milliseconds to wait before cut-off or zero to use the system default time-based cut-off.
+ * @param cutOffAfterCount
+ * the number of permission checks to process before cut-off or zero to use the system default count-based cut-off.
+ * @return a Collection
of the same type but including the {@link PermissionCheckCollection} interface
+ */
+ @SuppressWarnings("unchecked")
+ public static Collection create(
+ Collection collection,
+ int targetResultCount, long cutOffAfterTimeMs, int cutOffAfterCount)
+ {
+ if (targetResultCount <= 0)
+ {
+ targetResultCount = collection.size();
+ }
+ // Create the mixin
+ DelegatingIntroductionInterceptor mixin = new PermissionCheckCollectionMixin<>(
+ targetResultCount,
+ cutOffAfterTimeMs,
+ cutOffAfterCount);
+ // Create the advisor
+ IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(mixin, PermissionCheckCollection.class);
+ // Create Proxy
+ return (Collection) ProxyFactoryUtils.createProxy(collection, advisor);
+ }
+ }
+}
diff --git a/repository/src/main/java/org/alfresco/repo/security/permissions/PermissionCheckedCollection.java b/repository/src/main/java/org/alfresco/repo/security/permissions/PermissionCheckedCollection.java
index 305cb9cd05..b855219951 100644
--- a/repository/src/main/java/org/alfresco/repo/security/permissions/PermissionCheckedCollection.java
+++ b/repository/src/main/java/org/alfresco/repo/security/permissions/PermissionCheckedCollection.java
@@ -2,161 +2,160 @@
* #%L
* Alfresco Repository
* %%
- * Copyright (C) 2005 - 2016 Alfresco Software Limited
+ * Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
- * This file is part of the Alfresco software.
- * If the software was purchased under a paid Alfresco license, the terms of
- * the paid license agreement will prevail. Otherwise, the software is
+ * This file is part of the Alfresco software.
+ * If the software was purchased under a paid Alfresco license, the terms of
+ * the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
- *
+ *
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
- *
+ *
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see .
* #L%
*/
-package org.alfresco.repo.security.permissions;
-
-import java.util.Collection;
-
-import org.springframework.aop.IntroductionAdvisor;
-import org.springframework.aop.framework.ProxyFactory;
-import org.springframework.aop.support.DefaultIntroductionAdvisor;
-import org.springframework.aop.support.DelegatingIntroductionInterceptor;
-
-/**
- * Interface for collection-based results that carry extra information
- * about the state of permission cut-offs.
- *
- * @author Derek Hulley
- * @since 4.0
- */
-public interface PermissionCheckedCollection
-{
- /**
- * Check if the results have been truncated by permission check limits.
- *
- * @return true - if the results (usually a collection) have been
- * cut off by permission check limits
- */
- boolean isCutOff();
-
- /**
- * Get the number of objects in the original (unfiltered) collection that did
- * not have any permission checks.
- *
- * @return number of entries from the original collection that were not checked
- */
- int sizeUnchecked();
-
- /**
- * Get the number of objects in the original (unfiltered) collection.
- *
- * @return number of entries in the original, pre-checked collection
- */
- int sizeOriginal();
-
- /**
- * Helper 'introduction' to allow simple addition of the {@link PermissionCheckedCollection} interface to
- * existing collections.
- *
- * @param the type of the Collection
in use
- *
- * @author Derek Hulley
- * @since 4.0
- */
- @SuppressWarnings("serial")
- public static class PermissionCheckedCollectionMixin extends DelegatingIntroductionInterceptor implements PermissionCheckedCollection
- {
- private final boolean isCutOff;
- private final int sizeUnchecked;
- private final int sizeOriginal;
- private PermissionCheckedCollectionMixin(boolean isCutOff, int sizeUnchecked, int sizeOriginal)
- {
- super();
- this.isCutOff = isCutOff;
- this.sizeUnchecked = sizeUnchecked;
- this.sizeOriginal = sizeOriginal;
- }
- @Override
- public boolean isCutOff()
- {
- return isCutOff;
- }
- @Override
- public int sizeUnchecked()
- {
- return sizeUnchecked;
- }
- @Override
- public int sizeOriginal()
- {
- return sizeOriginal;
- }
- /**
- * Helper method to create a {@link PermissionCheckedCollection} from an existing Collection
- * by applying the same values as present on a potentially permission-checked source. If the
- * existing checked source is NOT permission-checked, then the collection will not be
- * decorated.
- *
- * @param the type of the Collection
- * @param collection the Collection
to proxy
- * @param checkedSource a collection that might implement {@link PermissionCheckedCollection}
- * @return a Collection
of the same type but including the
- * {@link PermissionCheckedCollection} interface
- */
- public static final Collection create(
- Collection collection, Collection> checkedSource)
- {
- if (checkedSource instanceof PermissionCheckedCollection)
- {
- PermissionCheckedCollection> source = (PermissionCheckedCollection>) checkedSource;
- return create(collection, source.isCutOff(), source.sizeUnchecked(), source.sizeOriginal());
- }
- else
- {
- return collection;
- }
- }
- /**
- * Helper method to create a {@link PermissionCheckedCollection} from an existing Collection
- *
- * @param the type of the Collection
- * @param collection the Collection
to proxy
- * @param isCutOff true if permission checking was cut off before completion
- * @param sizeUnchecked number of entries from the original collection that were not checked
- * @param sizeOriginal number of entries in the original, pre-checked collection
- * @return a Collection
of the same type but including the
- * {@link PermissionCheckedCollection} interface
- */
- @SuppressWarnings("unchecked")
- public static final Collection create(
- Collection collection,
- boolean isCutOff, int sizeUnchecked, int sizeOriginal)
- {
- // Create the mixin
- DelegatingIntroductionInterceptor mixin = new PermissionCheckedCollectionMixin(
- isCutOff,
- sizeUnchecked,
- sizeOriginal
- );
- // Create the advisor
- IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(mixin, PermissionCheckedCollection.class);
- // Proxy
- ProxyFactory pf = new ProxyFactory(collection);
- pf.addAdvisor(advisor);
- Object proxiedObject = pf.getProxy();
-
- // Done
- return (Collection) proxiedObject;
- }
- }
-}
+package org.alfresco.repo.security.permissions;
+
+import java.util.Collection;
+
+import org.springframework.aop.IntroductionAdvisor;
+import org.springframework.aop.support.DefaultIntroductionAdvisor;
+import org.springframework.aop.support.DelegatingIntroductionInterceptor;
+
+/**
+ * Interface for collection-based results that carry extra information about the state of permission cut-offs.
+ *
+ * @author Derek Hulley
+ * @since 4.0
+ */
+public interface PermissionCheckedCollection
+{
+ /**
+ * Check if the results have been truncated by permission check limits.
+ *
+ * @return true - if the results (usually a collection) have been cut off by permission check limits
+ */
+ boolean isCutOff();
+
+ /**
+ * Get the number of objects in the original (unfiltered) collection that did not have any permission checks.
+ *
+ * @return number of entries from the original collection that were not checked
+ */
+ int sizeUnchecked();
+
+ /**
+ * Get the number of objects in the original (unfiltered) collection.
+ *
+ * @return number of entries in the original, pre-checked collection
+ */
+ int sizeOriginal();
+
+ /**
+ * Helper 'introduction' to allow simple addition of the {@link PermissionCheckedCollection} interface to existing collections.
+ *
+ * @param
+ * the type of the Collection
in use
+ *
+ * @author Derek Hulley
+ * @since 4.0
+ */
+ @SuppressWarnings("serial")
+ class PermissionCheckedCollectionMixin extends DelegatingIntroductionInterceptor implements PermissionCheckedCollection
+ {
+ private final boolean isCutOff;
+ private final int sizeUnchecked;
+ private final int sizeOriginal;
+
+ private PermissionCheckedCollectionMixin(boolean isCutOff, int sizeUnchecked, int sizeOriginal)
+ {
+ super();
+ this.isCutOff = isCutOff;
+ this.sizeUnchecked = sizeUnchecked;
+ this.sizeOriginal = sizeOriginal;
+ }
+
+ @Override
+ public boolean isCutOff()
+ {
+ return isCutOff;
+ }
+
+ @Override
+ public int sizeUnchecked()
+ {
+ return sizeUnchecked;
+ }
+
+ @Override
+ public int sizeOriginal()
+ {
+ return sizeOriginal;
+ }
+
+ /**
+ * Helper method to create a {@link PermissionCheckedCollection} from an existing Collection
by applying the same values as present on a potentially permission-checked source. If the existing checked source is NOT permission-checked, then the collection will not be decorated.
+ *
+ * @param
+ * the type of the Collection
+ * @param collection
+ * the Collection
to proxy
+ * @param checkedSource
+ * a collection that might implement {@link PermissionCheckedCollection}
+ * @return a Collection
of the same type but including the {@link PermissionCheckedCollection} interface
+ */
+ public static Collection create(
+ Collection collection, Collection> checkedSource)
+ {
+ if (checkedSource instanceof PermissionCheckedCollection)
+ {
+ PermissionCheckedCollection> source = (PermissionCheckedCollection>) checkedSource;
+ return create(collection, source.isCutOff(), source.sizeUnchecked(), source.sizeOriginal());
+ }
+ else
+ {
+ return collection;
+ }
+ }
+
+ /**
+ * Helper method to create a {@link PermissionCheckedCollection} from an existing Collection
+ *
+ * @param
+ * the type of the Collection
+ * @param collection
+ * the Collection
to proxy
+ * @param isCutOff
+ * true if permission checking was cut off before completion
+ * @param sizeUnchecked
+ * number of entries from the original collection that were not checked
+ * @param sizeOriginal
+ * number of entries in the original, pre-checked collection
+ * @return a Collection
of the same type but including the {@link PermissionCheckedCollection} interface
+ */
+ @SuppressWarnings("unchecked")
+ public static Collection create(
+ Collection collection,
+ boolean isCutOff, int sizeUnchecked, int sizeOriginal)
+ {
+ // Create the mixin
+ DelegatingIntroductionInterceptor mixin = new PermissionCheckedCollectionMixin<>(
+ isCutOff,
+ sizeUnchecked,
+ sizeOriginal);
+ // Create the advisor
+ IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(mixin, PermissionCheckedCollection.class);
+ // Create Proxy
+ return (Collection) ProxyFactoryUtils.createProxy(collection, advisor);
+ }
+ }
+}
diff --git a/repository/src/main/java/org/alfresco/repo/security/permissions/ProxyFactoryUtils.java b/repository/src/main/java/org/alfresco/repo/security/permissions/ProxyFactoryUtils.java
new file mode 100644
index 0000000000..88333e79b4
--- /dev/null
+++ b/repository/src/main/java/org/alfresco/repo/security/permissions/ProxyFactoryUtils.java
@@ -0,0 +1,59 @@
+/*
+ * #%L
+ * Alfresco Repository
+ * %%
+ * Copyright (C) 2024 Alfresco Software Limited
+ * %%
+ * This file is part of the Alfresco software.
+ * If the software was purchased under a paid Alfresco license, the terms of
+ * the paid license agreement will prevail. Otherwise, the software is
+ * provided under the following open source license terms:
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ * #L%
+ */
+package org.alfresco.repo.security.permissions;
+
+import java.util.Collection;
+import java.util.Deque;
+import java.util.List;
+
+import org.springframework.aop.IntroductionAdvisor;
+import org.springframework.aop.framework.ProxyFactory;
+
+class ProxyFactoryUtils
+{
+ private ProxyFactoryUtils()
+ {}
+
+ /**
+ * Delegate creation of {@link ProxyFactory} and proxy to have control over it in one place.
+ *
+ * @param collection
+ * given collection for ProxyFactory.
+ * @param advisor
+ * given advisor for ProxyFactory.
+ * @return the proxy object.
+ */
+ protected static Object createProxy(Collection> collection, IntroductionAdvisor advisor)
+ {
+ ProxyFactory pf = new ProxyFactory(collection);
+ pf.addAdvisor(advisor);
+ if (pf.isInterfaceProxied(List.class) && pf.isInterfaceProxied(Deque.class))
+ {
+ pf.removeInterface(Deque.class);
+ }
+ return pf.getProxy();
+ }
+}