ACS-8843 Investigate Java 21 compatibility (#2960)

* [ACS-8843] Delegate creation of proxy to one place

Co-authored-by: Kacper Magdziarz <kacper.magdziarz@hyland.com>
This commit is contained in:
Piotr Żurek
2024-10-04 14:31:56 +02:00
committed by GitHub
parent 60a31112ea
commit 674fa8d7e0
3 changed files with 327 additions and 275 deletions

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2024 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
@@ -28,13 +28,11 @@ package org.alfresco.repo.security.permissions;
import java.util.Collection; import java.util.Collection;
import org.springframework.aop.IntroductionAdvisor; import org.springframework.aop.IntroductionAdvisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultIntroductionAdvisor; import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.support.DelegatingIntroductionInterceptor; import org.springframework.aop.support.DelegatingIntroductionInterceptor;
/** /**
* Interface for collection-based results that describe permission filtering * Interface for collection-based results that describe permission filtering behaviour around cut-off limits.
* behaviour around cut-off limits.
* *
* @author Derek Hulley * @author Derek Hulley
* @since 4.0 * @since 4.0
@@ -42,16 +40,15 @@ import org.springframework.aop.support.DelegatingIntroductionInterceptor;
public interface PermissionCheckCollection<T> public interface PermissionCheckCollection<T>
{ {
/** /**
* Get the desired number of results. Permission checks can stop once the number of * Get the desired number of results. Permission checks can stop once the number of return objects reaches this number.
* return objects reaches this number.
* *
* @return the number of results desired * @return the number of results desired
*/ */
int getTargetResultCount(); int getTargetResultCount();
/** /**
* Get the maximum time for permission checks to execute before cutting the results off. * Get the maximum time for permission checks to execute before cutting the results off. <br/>
* <br/>Zero: Ignore this value. * Zero: Ignore this value.
* *
* @return the time allowed for permission checks before cutoff * @return the time allowed for permission checks before cutoff
*/ */
@@ -65,16 +62,16 @@ public interface PermissionCheckCollection<T>
int getCutOffAfterCount(); int getCutOffAfterCount();
/** /**
* Helper 'introduction' to allow simple addition of the {@link PermissionCheckCollection} interface to * Helper 'introduction' to allow simple addition of the {@link PermissionCheckCollection} interface to existing collections.
* existing collections.
* *
* @param <T> the type of the <code>Collection</code> in use * @param <T>
* the type of the <code>Collection</code> in use
* *
* @author Derek Hulley * @author Derek Hulley
* @since 4.0 * @since 4.0
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
public static class PermissionCheckCollectionMixin<T> extends DelegatingIntroductionInterceptor implements PermissionCheckCollection<T> class PermissionCheckCollectionMixin<T> extends DelegatingIntroductionInterceptor implements PermissionCheckCollection<T>
{ {
private final int targetResultCount; private final int targetResultCount;
private final long cutOffAfterTimeMs; private final long cutOffAfterTimeMs;
@@ -117,18 +114,20 @@ public interface PermissionCheckCollection<T>
/** /**
* Helper method to create a {@link PermissionCheckCollection} from an existing <code>Collection</code> * Helper method to create a {@link PermissionCheckCollection} from an existing <code>Collection</code>
* *
* @param <TT> the type of the <code>Collection</code> * @param <TT>
* @param collection the <code>Collection</code> to proxy * the type of the <code>Collection</code>
* @param targetResultCount the desired number of results or default to the collection size * @param collection
* @param cutOffAfterTimeMs the number of milliseconds to wait before cut-off or zero to use the system default * the <code>Collection</code> to proxy
* time-based cut-off. * @param targetResultCount
* @param cutOffAfterCount the number of permission checks to process before cut-off or zero to use the system default * the desired number of results or default to the collection size
* count-based cut-off. * @param cutOffAfterTimeMs
* @return a <code>Collection</code> of the same type but including the * the number of milliseconds to wait before cut-off or zero to use the system default time-based cut-off.
* {@link PermissionCheckCollection} interface * @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 <code>Collection</code> of the same type but including the {@link PermissionCheckCollection} interface
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static final <TT> Collection<TT> create( public static <TT> Collection<TT> create(
Collection<TT> collection, Collection<TT> collection,
int targetResultCount, long cutOffAfterTimeMs, int cutOffAfterCount) int targetResultCount, long cutOffAfterTimeMs, int cutOffAfterCount)
{ {
@@ -137,19 +136,14 @@ public interface PermissionCheckCollection<T>
targetResultCount = collection.size(); targetResultCount = collection.size();
} }
// Create the mixin // Create the mixin
DelegatingIntroductionInterceptor mixin = new PermissionCheckCollectionMixin<Integer>( DelegatingIntroductionInterceptor mixin = new PermissionCheckCollectionMixin<>(
targetResultCount, targetResultCount,
cutOffAfterTimeMs, cutOffAfterTimeMs,
cutOffAfterCount); cutOffAfterCount);
// Create the advisor // Create the advisor
IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(mixin, PermissionCheckCollection.class); IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(mixin, PermissionCheckCollection.class);
// Proxy // Create Proxy
ProxyFactory pf = new ProxyFactory(collection); return (Collection<TT>) ProxyFactoryUtils.createProxy(collection, advisor);
pf.addAdvisor(advisor);
Object proxiedObject = pf.getProxy();
// Done
return (Collection<TT>) proxiedObject;
} }
} }
} }

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2024 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
@@ -28,13 +28,11 @@ package org.alfresco.repo.security.permissions;
import java.util.Collection; import java.util.Collection;
import org.springframework.aop.IntroductionAdvisor; import org.springframework.aop.IntroductionAdvisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultIntroductionAdvisor; import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.support.DelegatingIntroductionInterceptor; import org.springframework.aop.support.DelegatingIntroductionInterceptor;
/** /**
* Interface for collection-based results that carry extra information * Interface for collection-based results that carry extra information about the state of permission cut-offs.
* about the state of permission cut-offs.
* *
* @author Derek Hulley * @author Derek Hulley
* @since 4.0 * @since 4.0
@@ -44,14 +42,12 @@ public interface PermissionCheckedCollection<T>
/** /**
* Check if the results have been truncated by permission check limits. * Check if the results have been truncated by permission check limits.
* *
* @return <tt>true</tt> - if the results (usually a collection) have been * @return <tt>true</tt> - if the results (usually a collection) have been cut off by permission check limits
* cut off by permission check limits
*/ */
boolean isCutOff(); boolean isCutOff();
/** /**
* Get the number of objects in the original (unfiltered) collection that did * Get the number of objects in the original (unfiltered) collection that did <b>not</b> have any permission checks.
* <b>not</b> have any permission checks.
* *
* @return number of entries from the original collection that were not checked * @return number of entries from the original collection that were not checked
*/ */
@@ -65,20 +61,21 @@ public interface PermissionCheckedCollection<T>
int sizeOriginal(); int sizeOriginal();
/** /**
* Helper 'introduction' to allow simple addition of the {@link PermissionCheckedCollection} interface to * Helper 'introduction' to allow simple addition of the {@link PermissionCheckedCollection} interface to existing collections.
* existing collections.
* *
* @param <T> the type of the <code>Collection</code> in use * @param <T>
* the type of the <code>Collection</code> in use
* *
* @author Derek Hulley * @author Derek Hulley
* @since 4.0 * @since 4.0
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
public static class PermissionCheckedCollectionMixin<T> extends DelegatingIntroductionInterceptor implements PermissionCheckedCollection<T> class PermissionCheckedCollectionMixin<T> extends DelegatingIntroductionInterceptor implements PermissionCheckedCollection<T>
{ {
private final boolean isCutOff; private final boolean isCutOff;
private final int sizeUnchecked; private final int sizeUnchecked;
private final int sizeOriginal; private final int sizeOriginal;
private PermissionCheckedCollectionMixin(boolean isCutOff, int sizeUnchecked, int sizeOriginal) private PermissionCheckedCollectionMixin(boolean isCutOff, int sizeUnchecked, int sizeOriginal)
{ {
super(); super();
@@ -86,34 +83,37 @@ public interface PermissionCheckedCollection<T>
this.sizeUnchecked = sizeUnchecked; this.sizeUnchecked = sizeUnchecked;
this.sizeOriginal = sizeOriginal; this.sizeOriginal = sizeOriginal;
} }
@Override @Override
public boolean isCutOff() public boolean isCutOff()
{ {
return isCutOff; return isCutOff;
} }
@Override @Override
public int sizeUnchecked() public int sizeUnchecked()
{ {
return sizeUnchecked; return sizeUnchecked;
} }
@Override @Override
public int sizeOriginal() public int sizeOriginal()
{ {
return sizeOriginal; return sizeOriginal;
} }
/** /**
* Helper method to create a {@link PermissionCheckedCollection} from an existing <code>Collection</code> * Helper method to create a {@link PermissionCheckedCollection} from an existing <code>Collection</code> by applying the same values as present on a potentially permission-checked source. If the existing checked source is <b>NOT</b> permission-checked, then the collection will not be decorated.
* by applying the same values as present on a potentially permission-checked source. If the
* existing checked source is <b>NOT</b> permission-checked, then the collection will not be
* decorated.
* *
* @param <TT> the type of the <code>Collection</code> * @param <TT>
* @param collection the <code>Collection</code> to proxy * the type of the <code>Collection</code>
* @param checkedSource a collection that might implement {@link PermissionCheckedCollection} * @param collection
* @return a <code>Collection</code> of the same type but including the * the <code>Collection</code> to proxy
* {@link PermissionCheckedCollection} interface * @param checkedSource
* a collection that might implement {@link PermissionCheckedCollection}
* @return a <code>Collection</code> of the same type but including the {@link PermissionCheckedCollection} interface
*/ */
public static final <TT> Collection<TT> create( public static <TT> Collection<TT> create(
Collection<TT> collection, Collection<?> checkedSource) Collection<TT> collection, Collection<?> checkedSource)
{ {
if (checkedSource instanceof PermissionCheckedCollection) if (checkedSource instanceof PermissionCheckedCollection)
@@ -126,37 +126,36 @@ public interface PermissionCheckedCollection<T>
return collection; return collection;
} }
} }
/** /**
* Helper method to create a {@link PermissionCheckedCollection} from an existing <code>Collection</code> * Helper method to create a {@link PermissionCheckedCollection} from an existing <code>Collection</code>
* *
* @param <TT> the type of the <code>Collection</code> * @param <TT>
* @param collection the <code>Collection</code> to proxy * the type of the <code>Collection</code>
* @param isCutOff <tt>true</tt> if permission checking was cut off before completion * @param collection
* @param sizeUnchecked number of entries from the original collection that were not checked * the <code>Collection</code> to proxy
* @param sizeOriginal number of entries in the original, pre-checked collection * @param isCutOff
* @return a <code>Collection</code> of the same type but including the * <tt>true</tt> if permission checking was cut off before completion
* {@link PermissionCheckedCollection} interface * @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 <code>Collection</code> of the same type but including the {@link PermissionCheckedCollection} interface
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static final <TT> Collection<TT> create( public static <TT> Collection<TT> create(
Collection<TT> collection, Collection<TT> collection,
boolean isCutOff, int sizeUnchecked, int sizeOriginal) boolean isCutOff, int sizeUnchecked, int sizeOriginal)
{ {
// Create the mixin // Create the mixin
DelegatingIntroductionInterceptor mixin = new PermissionCheckedCollectionMixin<Integer>( DelegatingIntroductionInterceptor mixin = new PermissionCheckedCollectionMixin<>(
isCutOff, isCutOff,
sizeUnchecked, sizeUnchecked,
sizeOriginal sizeOriginal);
);
// Create the advisor // Create the advisor
IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(mixin, PermissionCheckedCollection.class); IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(mixin, PermissionCheckedCollection.class);
// Proxy // Create Proxy
ProxyFactory pf = new ProxyFactory(collection); return (Collection<TT>) ProxyFactoryUtils.createProxy(collection, advisor);
pf.addAdvisor(advisor);
Object proxiedObject = pf.getProxy();
// Done
return (Collection<TT>) proxiedObject;
} }
} }
} }

View File

@@ -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 <http://www.gnu.org/licenses/>.
* #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();
}
}