From 674fa8d7e099293257eb2109e88b0111bdbba0cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20=C5=BBurek?= Date: Fri, 4 Oct 2024 14:31:56 +0200 Subject: [PATCH] ACS-8843 Investigate Java 21 compatibility (#2960) * [ACS-8843] Delegate creation of proxy to one place Co-authored-by: Kacper Magdziarz --- .../PermissionCheckCollection.java | 256 ++++++++-------- .../PermissionCheckedCollection.java | 287 +++++++++--------- .../permissions/ProxyFactoryUtils.java | 59 ++++ 3 files changed, 327 insertions(+), 275 deletions(-) create mode 100644 repository/src/main/java/org/alfresco/repo/security/permissions/ProxyFactoryUtils.java 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(); + } +}