public static < E > ProxyChannel < E > createProxy ( int capacity , Class < E > iFace , WaitStrategy waitStrategy , Class < ? extends ProxyChannelRingBuffer > backendType ) { if ( ! iFace . isInterface ( ) ) { throw new IllegalArgumentException ( "Not an interface: " + iFace ) ; } String generatedName = Type . getInternalName ( iFace ) + "$JCTools$ProxyChannel$" + backendType . getSimpleName ( ) ; Class < ? > preExisting = findExisting ( generatedName , iFace ) ; if ( preExisting != null ) { return instantiate ( preExisting , capacity , waitStrategy ) ; } List < Method > relevantMethods = findRelevantMethods ( iFace ) ; if ( relevantMethods . isEmpty ( ) ) { throw new IllegalArgumentException ( "Does not declare any abstract methods: " + iFace ) ; } // max number of reference arguments of any method int referenceMessageSize = 0 ; // max bytes required to store the primitive args of a call frame of any method int primitiveMessageSize = 0 ; for ( Method method : relevantMethods ) { int primitiveMethodSize = 0 ; int referenceCount = 0 ; for ( Class < ? > parameterType : method . getParameterTypes ( ) ) { if ( parameterType . isPrimitive ( ) ) { primitiveMethodSize += primitiveMemorySize ( parameterType ) ; } else { referenceCount ++ ; } } primitiveMessageSize = Math . max ( primitiveMessageSize , primitiveMethodSize ) ; referenceMessageSize = Math . max ( referenceMessageSize , referenceCount ) ; } // We need to add an int to this for the 'type' value on the message frame primitiveMessageSize += primitiveMemorySize ( int . class ) ; ClassWriter classWriter = new ClassWriter ( ClassWriter . COMPUTE_MAXS ) ; classWriter . visit ( Opcodes . V1_4 , Opcodes . ACC_SYNTHETIC | Opcodes . ACC_PUBLIC | Opcodes . ACC_FINAL , generatedName , null , Type . getInternalName ( backendType ) , new String [ ] { Type . getInternalName ( ProxyChannel . class ) , Type . getInternalName ( iFace ) } ) ; implementInstanceFields ( classWriter ) ; implementConstructor ( classWriter , backendType , generatedName , primitiveMessageSize , referenceMessageSize ) ; implementProxyInstance ( classWriter , iFace , generatedName ) ; implementProxy ( classWriter , iFace , generatedName ) ; implementUserMethods ( classWriter , relevantMethods , generatedName , backendType ) ; implementProcess ( classWriter , backendType , relevantMethods , iFace , generatedName ) ; classWriter . visitEnd ( ) ; synchronized ( ProxyChannelFactory . class ) { preExisting = findExisting ( generatedName , iFace ) ; if ( preExisting != null ) { return instantiate ( preExisting , capacity , waitStrategy ) ; } byte [ ] byteCode = classWriter . toByteArray ( ) ; printClassBytes ( byteCode ) ; // Caveat: The interface and JCTools must be on the same class loader. Maybe class loader should be an argument? Overload? Class < ? > definedClass = UnsafeAccess . UNSAFE . defineClass ( generatedName , byteCode , 0 , byteCode . length , iFace . getClassLoader ( ) , null ) ; return instantiate ( definedClass , capacity , waitStrategy ) ; } }
Create a proxy channel using a user supplied back end .