package org.zapodot.junit.ldap.internal.jndi; import net.bytebuddy.ByteBuddy; import net.bytebuddy.NamingStrategy; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.modifier.Visibility; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; import net.bytebuddy.implementation.FieldAccessor; import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.matcher.ElementMatchers; import javax.naming.Context; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; /** * A factory that creates delegating proxys for the Context and DirContext interfaces that delegates to an underlying InitialDirContext * <p> * This class is part of the internal API and may thus be changed or removed without warning */ public class ContextProxyFactory { private static final String DELEGATED_CONTEXT_FIELD_NAME = "delegatedContext"; private static final String DELEGATED_DIR_CONTEXT_FIELD_NAME = "delegatedDirContext"; private static final String DELEGATING_DIR_CONTEXT_PREFIX = "DelegatingDirContext"; private ContextProxyFactory() { } private static final Class<? extends Context> CONTEXT_PROXY_TYPE = new ByteBuddy().subclass(Context.class) .name(new NamingStrategy.PrefixingRandom("DelegatingContext") .subclass(new TypeDescription.Generic.OfNonGenericType.ForLoadedType(Context.class))) .method(ElementMatchers.<MethodDescription>isDeclaredBy(Context.class) .and(not(ElementMatchers.<MethodDescription>named("close"))) .and(not(ElementMatchers.<MethodDescription>isNative()))) .intercept(MethodDelegation.toField(DELEGATED_CONTEXT_FIELD_NAME)) .defineField(DELEGATED_CONTEXT_FIELD_NAME, Context.class, Visibility.PRIVATE) .method(isDeclaredBy(Context.class).and(named("close"))) .intercept(MethodDelegation.to(ContextInterceptor.class)) .implement(ContextProxy.class) .intercept(FieldAccessor.ofBeanProperty()) .make() .load(ContextProxyFactory.class .getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); private static final Class<? extends DirContext> DIR_CONTEXT_PROXY_TYPE = new ByteBuddy().subclass(DirContext.class) .name(new NamingStrategy.PrefixingRandom( DELEGATING_DIR_CONTEXT_PREFIX) .subclass(new TypeDescription.Generic.OfNonGenericType.ForLoadedType(DirContext.class))) .method(isDeclaredBy( DirContext.class)) .intercept(MethodDelegation .toField(DELEGATED_DIR_CONTEXT_FIELD_NAME)) .defineField(DELEGATED_DIR_CONTEXT_FIELD_NAME, DirContext.class, Visibility.PRIVATE) .implement(DirContextProxy.class) .intercept(FieldAccessor.ofBeanProperty()) .make() .load(ContextProxyFactory.class .getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); public static Context asDelegatingContext(final InitialDirContext initialDirContext) { return createProxy(initialDirContext); } private static Context createProxy(final InitialDirContext initialDirContext) { try { final Context contextDelegator = getDeclaredConstructor().newInstance(); ((ContextProxy) contextDelegator).setDelegatedContext(initialDirContext); return contextDelegator; } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new IllegalStateException(e); } } private static Constructor<? extends Context> getDeclaredConstructor() { try { return CONTEXT_PROXY_TYPE.getDeclaredConstructor(); } catch (NoSuchMethodException e) { throw new IllegalStateException("Can not find a default constructor for proxy class", e); } } public static DirContext asDelegatingDirContext(final InitialDirContext initialDirContext) { try { final DirContext dirContext = DIR_CONTEXT_PROXY_TYPE.newInstance(); ((DirContextProxy) dirContext).setDelegatedDirContext(initialDirContext); return dirContext; } catch (InstantiationException | IllegalAccessException e) { throw new IllegalStateException("Could not wrap DirContext", e); } } }