/** {@inheritDoc} */
  @SuppressWarnings("unchecked")
  @Override
  public <T> T createRingBufferProxy(
      final Class<T> proxyInterface,
      final Disruptor<ProxyMethodInvocation> disruptor,
      final OverflowStrategy overflowStrategy,
      final T implementation) {
    validator.validateAll(disruptor, proxyInterface);

    disruptor.handleEventsWith(createSingleImplementationHandlerChain(implementation));

    final ArgumentHolderGenerator argumentHolderGenerator = new ArgumentHolderGenerator(classPool);
    argumentHolderGenerator.createArgumentHolderClass(proxyInterface);

    prefillArgumentHolderObjects(disruptor.getRingBuffer(), argumentHolderGenerator);

    final Map<Method, Invoker> methodToInvokerMap =
        createMethodToInvokerMap(proxyInterface, argumentHolderGenerator);

    return generateProxy(
        proxyInterface,
        disruptor.getRingBuffer(),
        methodToInvokerMap,
        overflowStrategy,
        argumentHolderGenerator);
  }
  @SuppressWarnings("unchecked")
  private <T> Invoker generateInvoker(
      final Class<T> proxyInterface,
      final Method method,
      final ArgumentHolderGenerator argumentHolderGenerator) {
    final StringBuilder invokerClassName =
        new StringBuilder("_invoker")
            .append(proxyInterface.getSimpleName())
            .append(method.getName())
            .append('_')
            .append(getUniqueIdentifier());

    final Class<?>[] parameterTypes = method.getParameterTypes();
    for (final Class<?> paramType : parameterTypes) {
      if (paramType.isArray()) {
        invokerClassName.append(paramType.getComponentType().getSimpleName()).append("Array");
      } else {
        invokerClassName.append(paramType.getSimpleName());
      }
    }

    final CtClass ctClass = makeClass(classPool, invokerClassName.toString());
    addInterface(ctClass, Invoker.class, classPool);
    makePublicFinal(ctClass);

    final StringBuilder methodSrc =
        new StringBuilder("public void invokeWithArgumentHolder(")
            .append("Object")
            .append(" implementation, Object argumentHolder) {\n");

    if (parameterTypes.length != 0) {
      methodSrc
          .append("final ")
          .append(argumentHolderGenerator.getGeneratedClassName())
          .append(" holder = ")
          .append("(")
          .append(argumentHolderGenerator.getGeneratedClassName())
          .append(") argumentHolder;\n");
    }

    methodSrc
        .append("((")
        .append(proxyInterface.getName().replace('$', '.'))
        .append(")implementation).")
        .append(method.getName())
        .append('(');

    appendParametersFromArgumentHolder(parameterTypes, methodSrc, argumentHolderGenerator);

    methodSrc.append(");\n}\n");

    return generateInvoker(ctClass, methodSrc);
  }
  private void appendParametersFromArgumentHolder(
      final Class<?>[] parameterTypes,
      final StringBuilder methodSrc,
      final ArgumentHolderGenerator argumentHolderGenerator) {
    argumentHolderGenerator.resetFieldNames();
    for (int i = 0; i < parameterTypes.length; i++) {
      final Class<?> parameterType = parameterTypes[i];
      methodSrc
          .append("holder.")
          .append(argumentHolderGenerator.getNextFieldNameForType(parameterType));

      if (i < parameterTypes.length - 1) {
        methodSrc.append(", ");
      }
    }
  }
 private void prefillArgumentHolderObjects(
     final RingBuffer<ProxyMethodInvocation> ringBuffer,
     final ArgumentHolderGenerator argumentHolderGenerator) {
   final int bufferSize = ringBuffer.getBufferSize();
   for (int i = 0; i < bufferSize; i++) {
     ringBuffer
         .get(i)
         .setArgumentHolder(
             (Resetable) instantiate(argumentHolderGenerator.getGeneratedClass(), new Class[] {}));
   }
 }
  /** {@inheritDoc} */
  @Override
  @SuppressWarnings("unchecked")
  public <T> T createRingBufferProxy(
      final Class<T> proxyInterface,
      final Disruptor<ProxyMethodInvocation> disruptor,
      final OverflowStrategy overflowStrategy,
      final T... implementations) {
    validator.validateAll(disruptor, proxyInterface);

    if (implementations.length < 1) {
      throw new IllegalArgumentException("Must have at least one implementation");
    } else if (implementations.length == 1) {
      return createRingBufferProxy(proxyInterface, disruptor, overflowStrategy, implementations[0]);
    }

    final EventHandler<ProxyMethodInvocation>[] handlers = new EventHandler[implementations.length];
    for (int i = 0; i < implementations.length; i++) {
      handlers[i] = createMultipleImplementationHandlerChain(implementations[i]);
      disruptor.handleEventsWith(handlers[i]);
    }
    disruptor.after(handlers).then(new ResetHandler());

    final ArgumentHolderGenerator argumentHolderGenerator = new ArgumentHolderGenerator(classPool);
    argumentHolderGenerator.createArgumentHolderClass(proxyInterface);

    prefillArgumentHolderObjects(disruptor.getRingBuffer(), argumentHolderGenerator);

    final Map<Method, Invoker> methodToInvokerMap =
        createMethodToInvokerMap(proxyInterface, argumentHolderGenerator);

    return generateProxy(
        proxyInterface,
        disruptor.getRingBuffer(),
        methodToInvokerMap,
        overflowStrategy,
        argumentHolderGenerator);
  }
  private void createRingBufferPublisherMethod(
      final CtClass ctClass,
      final Method method,
      final Invoker invoker,
      final OverflowStrategy overflowStrategy,
      final ArgumentHolderGenerator argumentHolderGenerator) {
    final StringBuilder methodSrc =
        new StringBuilder("public void ").append(method.getName()).append("(");
    final Class<?>[] parameterTypes = method.getParameterTypes();
    char paramId = 'a';
    for (int i = 0, parameterTypesLength = parameterTypes.length; i < parameterTypesLength; i++) {
      final Class<?> parameterType = parameterTypes[i];

      if (parameterType.isArray()) {
        methodSrc
            .append(parameterType.getComponentType().getName())
            .append("[] ")
            .append(paramId++);
      } else {
        methodSrc.append(parameterType.getName()).append(' ').append(paramId++);
      }

      if (i < parameterTypesLength - 1) {
        methodSrc.append(", ");
      }
    }
    methodSrc.append(")\n{\n");

    methodSrc.append("messagePublicationListener.onPrePublish();\n");

    handleOverflowStrategy(overflowStrategy, methodSrc);

    methodSrc
        .append("final long sequence = ringBuffer.next();\n")
        .append("try\n")
        .append("{\n")
        .append(
            "final ProxyMethodInvocation proxyMethodInvocation = (ProxyMethodInvocation) ringBuffer.get(sequence);\n");

    final String argumentHolderClass = argumentHolderGenerator.getGeneratedClassName();

    methodSrc
        .append("final ")
        .append(argumentHolderClass)
        .append(" holder = (")
        .append(argumentHolderClass)
        .append(") proxyMethodInvocation.getArgumentHolder();\n");

    argumentHolderGenerator.resetFieldNames();

    for (int i = 0; i < parameterTypes.length; i++) {
      final Class<?> parameterType = parameterTypes[i];
      final String holderField = argumentHolderGenerator.getNextFieldNameForType(parameterType);
      methodSrc
          .append("holder.")
          .append(holderField)
          .append(" = ")
          .append((char) ('a' + i))
          .append(";");
    }

    methodSrc
        .append("proxyMethodInvocation.setInvoker(_")
        .append(invoker.getClass().getName())
        .append(");\n")
        .append("}\n")
        .append("catch(Throwable t){t.printStackTrace();}\n")
        .append("finally\n")
        .append("{\n")
        .append("ringBuffer.publish(sequence);\n")
        .append("messagePublicationListener.onPostPublish();\n")
        .append("}\n");
    methodSrc.append("}\n");

    createMethod(ctClass, methodSrc.toString());
  }