From 2d856d3567499ceacb1ae700dc881325ccf21ad7 Mon Sep 17 00:00:00 2001 From: Lin Gao Date: Wed, 23 Aug 2017 13:13:39 +0800 Subject: [PATCH] [EJBCLIENT-253] Emulate org.jboss.ejb.client.EJBClientContext.registerInterceptor(ILorg/jboss/ejb/client/EJBClientInterceptor;) --- .../jboss/ejb/client/EJBClientContext.java | 100 +++++++++++++++++- .../ejb/client/EJBClientInterceptor.java | 33 ++++++ 2 files changed, 132 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jboss/ejb/client/EJBClientContext.java b/src/main/java/org/jboss/ejb/client/EJBClientContext.java index e3f1e3081..f38dfeea8 100644 --- a/src/main/java/org/jboss/ejb/client/EJBClientContext.java +++ b/src/main/java/org/jboss/ejb/client/EJBClientContext.java @@ -38,6 +38,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -73,6 +74,10 @@ public final class EJBClientContext extends Attachable implements Contextual registrationsUpdater = AtomicReferenceFieldUpdater.newUpdater(EJBClientContext.class, EJBClientInterceptor.Registration[].class, "registrations"); + private volatile EJBClientInterceptor.Registration[] registrations = NO_INTERCEPTORS; + /** * The discovery attribute name which contains the application and module name of the located EJB. */ @@ -329,6 +334,90 @@ static InterceptorList getClassPathInterceptorList() { } } + /** + * Register a client interceptor with this client context. + *

+ * If the passed clientInterceptor is already added to this context, then this method just returns the + * old {@link org.jboss.ejb.client.EJBClientInterceptor.Registration}. + * + *

+ * Note: If an interceptor is added or removed after a proxy is used, this will not affect the proxy interceptor list. + *

+ * + * @param priority the absolute priority of this interceptor (lower runs earlier; higher runs later) + * @param clientInterceptor the interceptor to register + * @return a handle which may be used to later remove this registration + * + * @deprecated Please use EJBClientContext.Builder to manipulate the EJBClientInterceptors. + */ + @Deprecated + public EJBClientInterceptor.Registration registerInterceptor(final int priority, final EJBClientInterceptor clientInterceptor) throws IllegalArgumentException { + Assert.checkNotNullParam("clientInterceptor", clientInterceptor); + final EJBClientInterceptor.Registration newRegistration = new EJBClientInterceptor.Registration(this, clientInterceptor, priority); + EJBClientInterceptor.Registration[] oldRegistrations, newRegistrations; + do { + oldRegistrations = registrations; + for (EJBClientInterceptor.Registration oldRegistration : oldRegistrations) { + if (oldRegistration.getInterceptor() == clientInterceptor) { + if (oldRegistration.compareTo(newRegistration) == 0) { + // This means that a client interceptor which has already been added to this context, + // is being added with the same priority. In such cases, this new registration request + // is effectively a no-op and we just return the old registration + return oldRegistration; + } + } + } + final int length = oldRegistrations.length; + newRegistrations = Arrays.copyOf(oldRegistrations, length + 1); + newRegistrations[length] = newRegistration; + Arrays.sort(newRegistrations); + } while (!registrationsUpdater.compareAndSet(this, oldRegistrations, newRegistrations)); + return newRegistration; + } + + /** + * Removes the EJBClientInterceptor from current registrations. It is used by EJBClientInterceptor.Registration itself. + *

+ * Note: If an interceptor is added or removed after a proxy is used, this will not affect the proxy interceptor list. + *

+ * + * @param registration the EJBClientInterceptor registration handler + * + * @deprecated Please use EJBClientContext.Builder to manipulate the EJBClientInterceptors. + */ + @Deprecated + void removeInterceptor(final EJBClientInterceptor.Registration registration) { + EJBClientInterceptor.Registration[] oldRegistrations, newRegistrations; + do { + oldRegistrations = registrations; + newRegistrations = null; + final int length = oldRegistrations.length; + final int newLength = length - 1; + if (length == 1) { + if (oldRegistrations[0] == registration) { + newRegistrations = NO_INTERCEPTORS; + } + } else { + for (int i = 0; i < length; i++) { + if (oldRegistrations[i] == registration) { + if (i == newLength) { + newRegistrations = Arrays.copyOf(oldRegistrations, newLength); + break; + } else { + newRegistrations = new EJBClientInterceptor.Registration[newLength]; + if (i > 0) System.arraycopy(oldRegistrations, 0, newRegistrations, 0, i); + System.arraycopy(oldRegistrations, i + 1, newRegistrations, i, newLength - i); + break; + } + } + } + } + if (newRegistrations == null) { + return; + } + } while (!registrationsUpdater.compareAndSet(this, oldRegistrations, newRegistrations)); + } + /** * Get the context manager. Simply calls the {@code static} method {@link #getContextManager()}. * @@ -740,7 +829,16 @@ InterceptorList getClassPathInterceptors() { } InterceptorList getGlobalInterceptors() { - return globalInterceptors; + return globalInterceptors.combine(registeredInterceptors()); + } + + private InterceptorList registeredInterceptors() { + final EJBClientInterceptor.Registration[] currentRegistrations = this.registrations.clone(); + ArrayList al = new ArrayList<>(); + for (EJBClientInterceptor.Registration r: currentRegistrations) { + al.add(EJBClientInterceptorInformation.forInstance(r.getInterceptor())); + } + return InterceptorList.ofList(al); } Map getConfiguredPerClassInterceptors() { diff --git a/src/main/java/org/jboss/ejb/client/EJBClientInterceptor.java b/src/main/java/org/jboss/ejb/client/EJBClientInterceptor.java index 8dc1993cf..11fa3bbc0 100644 --- a/src/main/java/org/jboss/ejb/client/EJBClientInterceptor.java +++ b/src/main/java/org/jboss/ejb/client/EJBClientInterceptor.java @@ -76,4 +76,37 @@ default void handleInvocationAsyncFailure(EJBClientInvocationContext context, Ex default SessionID handleSessionCreation(EJBSessionCreationInvocationContext context) throws Exception { return context.proceed(); } + + /** + * An interceptor registration handle. + * + * @deprecated Please use EJBClientContext.Builder to manipulate the EJBClientInterceptors. + */ + @Deprecated + class Registration implements Comparable { + private final EJBClientContext clientContext; + private final EJBClientInterceptor interceptor; + private final int priority; + + Registration(final EJBClientContext clientContext, final EJBClientInterceptor interceptor, final int priority) { + this.clientContext = clientContext; + this.interceptor = interceptor; + this.priority = priority; + } + + /** + * Remove this registration. + */ + public void remove() { + clientContext.removeInterceptor(this); + } + + EJBClientInterceptor getInterceptor() { + return interceptor; + } + + public int compareTo(final Registration o) { + return Integer.signum(priority - o.priority); + } + } }