package org.apache.markt;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.lang.reflect.Method;
import java.net.URLClassLoader;
import java.util.Vector;

public final class ClassLoaderLeak2 {
  static int exhaust() {
    int n = 0;
    Vector v = new Vector();
    try {
      while (true) {
        v.addElement(new byte[64000]);
        n++;
      }
    } catch (Throwable t) {}
    return n;
  }

  public static void main(final String[] args) throws Exception {
    createLoader();

    if (args.length > 0 && "exhaust".equals(args[0])) {
      long n = exhaust();
      System.out.println("exhaust = " + (n * 64000));
    } else {
      System.gc();
    }
    try {
      Thread.sleep(1000);
    } catch (Throwable t) {}

    if (args.length <= 1) {
      System.out.println("Failed to collect MyURLClassLoader");
      System.exit(1);
    } else {
      System.in.read(); // capture snapshot at this point
    }
  }

  public static void foo() {
    try {
      DocumentBuilderFactory.newInstance().newDocumentBuilder();
    }
    catch (ParserConfigurationException ignored) {
      // Ignore
    }
  }

  static class MyURLClassLoader extends URLClassLoader {
    MyURLClassLoader(java.net.URL[] urls) {
      super(urls, null);
    }
    public void finalize() {
      System.out.println("MyURLClassLoader is collected");
      System.exit(0);
    }
  }

  private static void createLoader() throws Exception {
    final ClassLoader myLoader = new MyURLClassLoader(
      ((URLClassLoader)ClassLoader.getSystemClassLoader()).getURLs());
    // load some class
    final Class<?> aClass = myLoader.loadClass(ClassLoaderLeak2.class.getName());
    final Method method = aClass.getDeclaredMethod("foo", new Class<?>[]{});
    method.invoke(null, new Object[]{});
  }
}
