//package de.bauerkirch.tools.bktimer;
package com.twc.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
import com.sun.deploy.cache.CachedJarFile;

// Requires deploy.jar

/**
 * Workaround http://bugs.sun.com/view_bug.do?bug_id=6967414
 * based on squaat's solution
 * 
 * @author Henning Pautsch, Bauer+Kirch GmbH
 */
public class JNLPClassLoaderFix {

	private Set<Object> hardlinkedReferences = new HashSet<Object>();

	public boolean fixIt() {
		try {
			Class<?> clazz = Class.forName("com.sun.jnlp.JNLPClassLoader");
			Object jnlpLoader = clazz.getMethod("getInstance").invoke(null);
			if (jnlpLoader == null) {
				System.out.println("Not running in JNLP-Mode. Ignoring Fix");
				return false;
			}
			Object launchDesc = clazz.getMethod("getLaunchDesc").invoke(jnlpLoader);
			Object resources = launchDesc.getClass().getMethod("getResources").invoke(launchDesc);
			Object[] allJars = (Object[]) resources.getClass()
				.getMethod("getEagerOrAllJarDescs", new Class[] { boolean.class }).invoke(resources, true);
			for (Object jarDesc : allJars) {
				URL descLocation = (URL) jarDesc.getClass().getMethod("getLocation").invoke(jarDesc);
				Method getJarMethod;
				CachedJarFile jarFile = null;
				getJarMethod = jnlpLoader.getClass().getMethod("getJarFile", new Class[] { URL.class });
				getJarMethod.setAccessible(true);
				jarFile = (CachedJarFile) getJarMethod.invoke(jnlpLoader, descLocation);

				assert (jarFile != null);

				Object signersResult = invokePrivateMethod(jarFile, "getSigners");
				Object signerMapResult = invokePrivateMethod(jarFile, "getSignerMap");
				Object codeSourceCacheResult = invokePrivateMethod(jarFile, "getCodeSourceCache");
				hardlinkedReferences.add(signersResult);
				hardlinkedReferences.add(signerMapResult);
				hardlinkedReferences.add(codeSourceCacheResult);

				Object signersRef = getPrivateFieldData(jarFile, "signersRef");
				Object signersMapRef = getPrivateFieldData(jarFile, "signerMapRef");
				Object codeSourceCacheRef = getPrivateFieldData(jarFile, "codeSourceCacheRef");
				hardlinkedReferences.add(signersRef);
				hardlinkedReferences.add(signersMapRef);
				hardlinkedReferences.add(codeSourceCacheRef);
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			return false;
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
			return false;
		} catch (SecurityException e) {
			e.printStackTrace();
			return false;
		} catch (IllegalAccessException e) {
			e.printStackTrace();
			return false;
		} catch (InvocationTargetException e) {
			e.printStackTrace();
			return false;
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	private Object invokePrivateMethod(final Object object, final String methodName) {
		Object result = null;
		try {
			Method method = object.getClass().getDeclaredMethod(methodName);
			method.setAccessible(true);
			result = method.invoke(object);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return result;
	}

	private Object getPrivateFieldData(final Object object, final String fieldName) {
		Object result = null;
		try {
			Field field = object.getClass().getDeclaredField(fieldName);
			field.setAccessible(true);
			result = field.get(object);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return result;
	}

}
