@Override
  public Object invoke(
      final Object self, final Method thisMethod, final Method proceed, final Object[] args)
      throws Throwable {
    if (Thread.currentThread().isInterrupted()) {
      throw new ContainerException("Thread.interrupt() requested.");
    }

    Callable<Object> task =
        new Callable<Object>() {
          @Override
          public Object call() throws Exception {
            try {
              if (thisMethod.getDeclaringClass().getName().equals(ForgeProxy.class.getName())) {
                if (thisMethod.getName().equals("getDelegate"))
                  return ClassLoaderInterceptor.this.getDelegate();
                if (thisMethod.getName().equals("getHandler"))
                  return ClassLoaderInterceptor.this.getHandler();
              }
            } catch (Exception e) {
            }

            ClassLoader previousLoader = null;
            Object result;
            try {
              previousLoader = setCurrentLoader(loader);

              if (thisMethod.equals(EQUALS_METHOD)) {
                Object object = args[0];
                Object unwrapped = Proxies.unwrap(object);
                args[0] = unwrapped;
              }

              result = thisMethod.invoke(delegate, args);
            } catch (InvocationTargetException e) {
              if (e.getCause() instanceof Exception) throw (Exception) e.getCause();
              throw e;
            } finally {
              setCurrentLoader(previousLoader);
            }
            return result;
          }
        };

    Object result = ClassLoaders.executeIn(loader, task);

    if (Thread.currentThread().isInterrupted()) {
      throw new ContainerException("Thread.interrupt() requested.");
    }

    return result;
  }
  @Override
  public TestResult invoke(final TestMethodExecutor testMethodExecutor) {
    try {
      if (testMethodExecutor == null) {
        throw new IllegalArgumentException("TestMethodExecutor must be specified");
      }

      final String testClassName = testMethodExecutor.getInstance().getClass().getName();

      Object testInstance = null;
      Class<?> testClass = null;
      try {
        final AddonRegistry addonRegistry = furnace.getAddonRegistry();

        waitUntilStable(furnace);
        System.out.println("Searching for test [" + testClassName + "]");

        for (Addon addon : addonRegistry.getAddons()) {
          if (addon.getStatus().isStarted()) {
            ServiceRegistry registry = addon.getServiceRegistry();
            ExportedInstance<?> exportedInstance = registry.getExportedInstance(testClassName);

            if (exportedInstance != null) {
              if (testInstance == null) {
                testInstance = exportedInstance.get();
                testClass = ClassLoaders.loadClass(addon.getClassLoader(), testClassName);
              } else {
                throw new IllegalStateException(
                    "Multiple test classes found in deployed addons. "
                        + "You must have only one @Deployment(testable=true\"); deployment");
              }
            }
          }
        }
      } catch (Exception e) {
        String message =
            "Error launching test "
                + testMethodExecutor.getInstance().getClass().getName()
                + "."
                + testMethodExecutor.getMethod().getName()
                + "()";
        System.out.println(message);
        throw new IllegalStateException(message, e);
      }

      if (testInstance != null) {
        try {
          TestResult result = null;
          try {
            try {
              testInstance =
                  ClassLoaderAdapterBuilder.callingLoader(getClass().getClassLoader())
                      .delegateLoader(testInstance.getClass().getClassLoader())
                      .enhance(testInstance, testClass);
            } catch (Exception e) {
              System.out.println(
                  "Could not enhance test class. Falling back to un-proxied invocation.");
            }

            Method method =
                testInstance.getClass().getMethod(testMethodExecutor.getMethod().getName());
            Annotation[] annotations = method.getAnnotations();

            for (Annotation annotation : annotations) {
              if ("org.junit.Ignore".equals(annotation.getClass().getName())) {
                result = new TestResult(Status.SKIPPED);
              }
            }

            if (result == null) {
              try {
                System.out.println(
                    "Executing test method: "
                        + testMethodExecutor.getInstance().getClass().getName()
                        + "."
                        + testMethodExecutor.getMethod().getName()
                        + "()");

                try {
                  invokeBefore(testInstance.getClass(), testInstance);
                  method.invoke(testInstance);
                  result = new TestResult(Status.PASSED);
                } catch (Exception e) {
                  Throwable rootCause = getRootCause(e);
                  // FORGE-1677
                  if (rootCause != null
                      && "org.junit.internal.AssumptionViolatedException"
                          .equals(rootCause.getClass().getName())) {
                    try {
                      // Due to classloader and serialization restrictions, we need to create a new
                      // instance
                      // of this class
                      Throwable thisClassloaderException =
                          (Throwable)
                              Class.forName("org.junit.internal.AssumptionViolatedException")
                                  .getConstructor(String.class)
                                  .newInstance(rootCause.getMessage());
                      thisClassloaderException.setStackTrace(rootCause.getStackTrace());
                      result = new TestResult(Status.SKIPPED, thisClassloaderException);
                    } catch (Exception ex) {
                      // ignore
                      result = new TestResult(Status.SKIPPED);
                    }
                  } else {
                    throw e;
                  }
                } finally {
                  invokeAfter(testInstance.getClass(), testInstance);
                }

              } catch (InvocationTargetException e) {
                if (e.getCause() != null && e.getCause() instanceof Exception)
                  throw (Exception) e.getCause();
                else throw e;
              }
            }
          } catch (AssertionError e) {
            result = new TestResult(Status.FAILED, e);
          } catch (Exception e) {
            result = new TestResult(Status.FAILED, e);

            Throwable cause = e.getCause();
            while (cause != null) {
              if (cause instanceof AssertionError) {
                result = new TestResult(Status.FAILED, cause);
                break;
              }
              cause = cause.getCause();
            }
          }
          return result;
        } catch (Exception e) {
          String message =
              "Error launching test "
                  + testMethodExecutor.getInstance().getClass().getName()
                  + "."
                  + testMethodExecutor.getMethod().getName()
                  + "()";
          System.out.println(message);
          throw new IllegalStateException(message, e);
        }
      } else {
        throw new IllegalStateException(
            "Test runner could not locate test class ["
                + testClassName
                + "] in any deployed Addon.");
      }
    } finally {
      furnace = null;
    }
  }