All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.zving.preloader.ReferenceCleaner Maven / Gradle / Ivy

There is a newer version: 0.3.0
Show newest version
package com.zving.preloader;

import java.beans.Introspector;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.concurrent.ThreadPoolExecutor;

public class ReferenceCleaner {
	private static final List JVM_THREAD_GROUP_NAMES = new ArrayList();
	private static final String JVN_THREAD_GROUP_SYSTEM = "system";
	private PreClassLoader loader;

	static {
		JVM_THREAD_GROUP_NAMES.add("system");
		JVM_THREAD_GROUP_NAMES.add("RMI Runtime");
	}

	public ReferenceCleaner(PreClassLoader loader) {
		this.loader = loader;
	}

	protected void clearReferences() {
		clearReferencesJdbc();

		clearReferencesThreads();

		clearReferencesThreadLocals();

		clearReferencesRmiTargets();

		clearReferencesStaticFinal();
		try {
			Class clazz = Class.forName("org.apache.commons.logging.LogFactory");
			if (clazz != null) {
				Method m = clazz.getMethod("release", new Class[] { ClassLoader.class });
				m.invoke(null, new Object[] { this.loader });
			}
		} catch (Exception localException) {
		}
		clearReferencesResourceBundles();

		Introspector.flushCaches();

		this.loader = null;
	}

	private final void clearReferencesJdbc() {
		InputStream is;
		byte classBytes[];
		int offset;
		is = loader.getResourceAsStream("com/zving/preloader/JdbcLeakPrevention.class");
		classBytes = new byte[2048];
		offset = 0;
		try {
			for (int read = is.read(classBytes, offset, classBytes.length - offset); read > -1; read = is.read(classBytes, offset, classBytes.length - offset)) {
				offset += read;
				if (offset == classBytes.length) {
					byte tmp[] = new byte[classBytes.length * 2];
					System.arraycopy(classBytes, 0, tmp, 0, classBytes.length);
					classBytes = tmp;
				}
			}

			Class lpClass = loader.defineClassEx("com.zving.preloader.JdbcLeakPrevention", classBytes, 0, offset, getClass().getProtectionDomain());
			Object obj = lpClass.newInstance();
			List driverNames = (List) obj.getClass().getMethod("clearJdbcDriverRegistrations", new Class[0]).invoke(obj, new Object[0]);
			String name;
			for (Iterator iterator = driverNames.iterator(); iterator.hasNext(); System.out.println((new StringBuilder("Clear JDBC reference success:")).append(name).toString()))
				name = (String) iterator.next();

		} catch (Exception e) {
			System.out.println((new StringBuilder("Clear JDBC reference failed:")).append(e.getMessage()).toString());
		}
		if (is != null)
			try {
				is.close();
			} catch (IOException ioexception) {
			}
	}

	private final void clearReferencesStaticFinal() {
		Class[] arr = new Class[this.loader.getLoadedClasses().size()];
		arr = (Class[]) this.loader.getLoadedClasses().toArray(arr);
		Class[] arrayOfClass1;
		int j = (arrayOfClass1 = arr).length;
		for (int k = 0; k < j; k++) {
			Class clazz = arrayOfClass1[k];
			try {
				Field[] fields = clazz.getDeclaredFields();
				for (int i = 0; i < fields.length; i++) {
					if (Modifier.isStatic(fields[i].getModifiers())) {
						fields[i].get(null);
						break;
					}
				}
			} catch (Throwable localThrowable1) {
			}
		}
		j = (arrayOfClass1 = arr).length;
		for (Class clazz : arrayOfClass1) {
			// Class clazz = arrayOfClass1[i];
			try {
				Field[] fields = clazz.getDeclaredFields();
				for (int i = 0; i < fields.length; i++) {
					Field field = fields[i];
					int mods = field.getModifiers();
					if ((!field.getType().isPrimitive()) && (field.getName().indexOf("$") == -1)) {
						if (Modifier.isStatic(mods)) {
							try {
								field.setAccessible(true);
								if (Modifier.isFinal(mods)) {
									if ((!field.getType().getName().startsWith("java.")) && (!field.getType().getName().startsWith("javax."))) {
										nullInstance(field.get(null));
									}
								} else {
									field.set(null, null);
								}
							} catch (Throwable localThrowable2) {
							}
						}
					}
				}
			} catch (Throwable t) {
				t.printStackTrace();
			}
		}
	}

	private void nullInstance(Object instance) {
		if (instance == null) {
			return;
		}
		Field[] fields = instance.getClass().getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {
			Field field = fields[i];
			int mods = field.getModifiers();
			if ((!field.getType().isPrimitive()) && (field.getName().indexOf("$") == -1)) {
				try {
					field.setAccessible(true);
					if ((!Modifier.isStatic(mods)) || (!Modifier.isFinal(mods))) {
						Object value = field.get(instance);
						if (value != null) {
							Class valueClass = value.getClass();
							if (loadedByThisOrChild(valueClass)) {
								field.set(instance, null);
							}
						}
					}
				} catch (Throwable t) {
					t.printStackTrace();
				}
			}
		}
	}

	protected boolean loadedByThisOrChild(Class clazz) {
		boolean result = false;
		for (ClassLoader classLoader = clazz.getClassLoader(); classLoader != null; classLoader = classLoader.getParent()) {
			if (classLoader.equals(this)) {
				result = true;
				break;
			}
		}
		return result;
	}

	private boolean threadNeedClear(Thread thread) {
		if (thread == Thread.currentThread()) {
			return false;
		}
		ThreadGroup tg = thread.getThreadGroup();
		if ((tg != null) && (JVM_THREAD_GROUP_NAMES.contains(tg.getName()))) {
			if (thread.getName().equals("Keep-Alive-Timer")) {
				thread.setContextClassLoader(this.loader.getParent());
			}
			return false;
		}
		if (!thread.isAlive()) {
			return false;
		}
		if (thread.getContextClassLoader() == this.loader) {
			return true;
		}
		if (thread.getClass().getClassLoader() == this.loader) {
			return true;
		}
		Object target = null;
		String[] arrayOfString;
		int j = (arrayOfString = new String[] { "target", "runnable", "action" }).length;
		for (int i = 0; i < j; i++) {
			String fieldName = arrayOfString[i];
			try {
				Field targetField = thread.getClass().getDeclaredField(fieldName);
				targetField.setAccessible(true);
				target = targetField.get(thread);
			} catch (Exception localException) {
			}
		}
		if ((target != null) && (target.getClass().getClassLoader() == this.loader)) {
			return true;
		}
		return false;
	}

	private void clearReferencesThreads() {
		Thread[] threads = getThreads();
		Thread[] arrayOfThread1;
		int j = (arrayOfThread1 = threads).length;
		for (int i = 0; i < j; i++) {
			Thread thread = arrayOfThread1[i];
			if (thread != null) {
				boolean clear = threadNeedClear(thread);
				if (clear) {
					if (thread.getClass().getName().startsWith("java.util.Timer")) {
						clearReferencesStopTimerThread(thread);
					} else {
						try {
							Object target = null;
							String[] arrayOfString;
							int m = (arrayOfString = new String[] { "target", "runnable", "action" }).length;
							for (int k = 0; k < m; k++) {
								String fieldName = arrayOfString[k];
								try {
									Field targetField = thread.getClass().getDeclaredField(fieldName);
									targetField.setAccessible(true);
									target = targetField.get(thread);
								} catch (NoSuchFieldException localNoSuchFieldException) {
								}
							}
							if ((target != null) && (target.getClass().getCanonicalName() != null)
									&& (target.getClass().getCanonicalName().equals("java.util.concurrent.ThreadPoolExecutor.Worker"))) {
								Field executorField = target.getClass().getDeclaredField("this$0");
								executorField.setAccessible(true);
								Object executor = executorField.get(target);
								if ((executor instanceof ThreadPoolExecutor)) {
									((ThreadPoolExecutor) executor).shutdownNow();
								}
							}
						} catch (Exception e) {
							e.printStackTrace();
						}
						try {
							thread.notifyAll();
							thread.interrupt();
						} catch (Throwable localThrowable) {
						}
						try {
							thread.stop();
						} catch (Throwable localThrowable1) {
						}
					}
				}
			}
		}
	}

	private void clearReferencesStopTimerThread(Thread thread) {
		try {
			try {
				Field newTasksMayBeScheduledField = thread.getClass().getDeclaredField("newTasksMayBeScheduled");
				newTasksMayBeScheduledField.setAccessible(true);
				Field queueField = thread.getClass().getDeclaredField("queue");
				queueField.setAccessible(true);

				Object queue = queueField.get(thread);

				Method clearMethod = queue.getClass().getDeclaredMethod("clear", new Class[0]);
				clearMethod.setAccessible(true);
				synchronized (queue) {
					newTasksMayBeScheduledField.setBoolean(thread, false);
					clearMethod.invoke(queue, new Object[0]);
					queue.notify();
				}
			} catch (NoSuchFieldException nfe) {
				Method cancelMethod = thread.getClass().getDeclaredMethod("cancel", new Class[0]);
				synchronized (thread) {
					cancelMethod.setAccessible(true);
					cancelMethod.invoke(thread, new Object[0]);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void clearReferencesThreadLocals() {
		Thread[] threads = getThreads();
		try {
			Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
			threadLocalsField.setAccessible(true);
			Field inheritableThreadLocalsField = Thread.class.getDeclaredField("inheritableThreadLocals");
			inheritableThreadLocalsField.setAccessible(true);

			Class tlmClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
			Field tableField = tlmClass.getDeclaredField("table");
			tableField.setAccessible(true);
			Method expungeStaleEntriesMethod = tlmClass.getDeclaredMethod("expungeStaleEntries", new Class[0]);
			expungeStaleEntriesMethod.setAccessible(true);
			for (int i = 0; i < threads.length; i++) {
				if (threads[i] != null) {
					Object threadLocalMap = threadLocalsField.get(threads[i]);
					if (threadLocalMap != null) {
						expungeStaleEntriesMethod.invoke(threadLocalMap, new Object[0]);
						checkThreadLocalMapForLeaks(threadLocalMap, tableField);
					}
					threadLocalMap = inheritableThreadLocalsField.get(threads[i]);
					if (threadLocalMap != null) {
						expungeStaleEntriesMethod.invoke(threadLocalMap, new Object[0]);
						checkThreadLocalMapForLeaks(threadLocalMap, tableField);
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void checkThreadLocalMapForLeaks(Object map, Field internalTableField)
			throws NoSuchMethodException, IllegalAccessException, NoSuchFieldException, InvocationTargetException {
		if (map != null) {
			Method mapRemove = map.getClass().getDeclaredMethod("remove", new Class[] { ThreadLocal.class });
			mapRemove.setAccessible(true);
			Object[] table = (Object[]) internalTableField.get(map);
			int staleEntriesCount = 0;
			if (table != null) {
				for (int j = 0; j < table.length; j++) {
					if (table[j] != null) {
						boolean remove = false;

						Object key = ((Reference) table[j]).get();
						if ((equals(key)) || (isLoadedByThisWebappClassLoader(key))) {
							remove = true;
						}
						Field valueField = table[j].getClass().getDeclaredField("value");
						valueField.setAccessible(true);
						Object value = valueField.get(table[j]);
						if ((equals(value)) || (isLoadedByThisWebappClassLoader(value))) {
							remove = true;
						}
						if (remove) {
							if (key == null) {
								staleEntriesCount++;
							} else {
								mapRemove.invoke(map, new Object[] { key });
							}
						}
					}
				}
			}
			if (staleEntriesCount > 0) {
				Method mapRemoveStale = map.getClass().getDeclaredMethod("expungeStaleEntries", new Class[0]);
				mapRemoveStale.setAccessible(true);
				mapRemoveStale.invoke(map, new Object[0]);
			}
		}
	}

	private boolean isLoadedByThisWebappClassLoader(Object o) {
		if (o == null) {
			return false;
		}
		for (ClassLoader loader = o.getClass().getClassLoader(); loader != null; loader = loader.getParent()) {
			if (loader == this.loader) {
				return true;
			}
		}
		return false;
	}

	private Thread[] getThreads() {
		ThreadGroup tg = Thread.currentThread().getThreadGroup();
		while (tg.getParent() != null) {
			tg = tg.getParent();
		}
		int threadCountGuess = tg.activeCount() + 50;
		Thread[] threads = new Thread[threadCountGuess];
		int threadCountActual = tg.enumerate(threads);
		while (threadCountActual == threadCountGuess) {
			threadCountGuess *= 2;
			threads = new Thread[threadCountGuess];

			threadCountActual = tg.enumerate(threads);
		}
		return threads;
	}

	private void clearReferencesRmiTargets() {
		try {
			Class objectTargetClass = Class.forName("sun.rmi.transport.Target");
			Field cclField = objectTargetClass.getDeclaredField("ccl");
			cclField.setAccessible(true);

			Class objectTableClass = Class.forName("sun.rmi.transport.ObjectTable");
			Field objTableField = objectTableClass.getDeclaredField("objTable");
			objTableField.setAccessible(true);
			Object objTable = objTableField.get(null);
			if (objTable == null) {
				return;
			}
			if ((objTable instanceof Map)) {
				Iterator iter = ((Map) objTable).values().iterator();
				while (iter.hasNext()) {
					Object obj = iter.next();
					Object cclObject = cclField.get(obj);
					if (this == cclObject) {
						iter.remove();
					}
				}
			}
			Field implTableField = objectTableClass.getDeclaredField("implTable");
			implTableField.setAccessible(true);
			Object implTable = implTableField.get(null);
			if (implTable == null) {
				return;
			}
			if ((implTable instanceof Map)) {
				Iterator iter = ((Map) implTable).values().iterator();
				while (iter.hasNext()) {
					Object obj = iter.next();
					Object cclObject = cclField.get(obj);
					if (this == cclObject) {
						iter.remove();
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void clearReferencesResourceBundles() {
		try {
			Field cacheListField = ResourceBundle.class.getDeclaredField("cacheList");
			cacheListField.setAccessible(true);

			Map cacheList = (Map) cacheListField.get(null);

			Set keys = cacheList.keySet();
			Field loaderRefField = null;

			Iterator keysIter = keys.iterator();
			while (keysIter.hasNext()) {
				Object key = keysIter.next();
				if (loaderRefField == null) {
					loaderRefField = key.getClass().getDeclaredField("loaderRef");
					loaderRefField.setAccessible(true);
				}
				WeakReference loaderRef = (WeakReference) loaderRefField.get(key);
				ClassLoader loader = (ClassLoader) loaderRef.get();
				while ((loader != null) && (loader != this.loader)) {
					loader = loader.getParent();
				}
				if (loader != null) {
					keysIter.remove();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy