/*******************************************************************************
* Copyright (c) 2013 Rene Schneider, GEBIT Solutions GmbH and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package de.gebit.integrity.ui.utils;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.launching.JavaRuntime;
/**
* A utility class containing methods to dynamically load classes into the eclipse workspace JVM.
*
* @author Rene Schneider - initial API and implementation
*
*/
public final class ClassLoadingUtil {
/**
* The class cache caches loaded classes.
*/
private Map<String, Class<?>> classCache = new Hashtable<String, Class<?>>();
/**
* The build listener is used to listen to workspace rebuilds and determines if Java-class-related changes have
* occurred.
*/
private JavaBuildListener buildListener = new JavaBuildListener();
/**
* Creates a new instance.
*/
public ClassLoadingUtil() {
IWorkspace tempWorkspace = ResourcesPlugin.getWorkspace();
tempWorkspace.addResourceChangeListener(buildListener, IResourceChangeEvent.POST_BUILD);
}
/**
* Finalizes an instance.
*/
protected void finalize() throws Throwable {
IWorkspace tempWorkspace = ResourcesPlugin.getWorkspace();
tempWorkspace.removeResourceChangeListener(buildListener);
};
/**
* Loads a class defined in a specific project into the Eclipse JVM.
*
* @param aClassName
* the fully qualified class name
* @param aProject
* the project where the class resides
* @return the loaded class
* @throws ClassNotFoundException
*/
public Class<?> loadClassFromWorkspace(String aClassName, IJavaProject aProject) throws ClassNotFoundException {
Class<?> tempClass = classCache.get(aClassName);
if (tempClass == null) {
try {
String[] tempClassPathEntries = JavaRuntime.computeDefaultRuntimeClassPath(aProject);
List<URL> tempUrlList = new ArrayList<URL>();
for (int i = 0; i < tempClassPathEntries.length; i++) {
String tempEntry = tempClassPathEntries[i];
IPath tempPath = new Path(tempEntry);
URL tempUrl = tempPath.toFile().toURI().toURL();
tempUrlList.add(tempUrl);
}
ClassLoader tempParentClassLoader = ClassLoadingUtil.class.getClassLoader();
URL[] tempUrls = (URL[]) tempUrlList.toArray(new URL[tempUrlList.size()]);
try (URLClassLoader tempClassLoader = new URLClassLoader(tempUrls, tempParentClassLoader)) {
tempClass = tempClassLoader.loadClass(aClassName);
if (tempClass != null) {
classCache.put(aClassName, tempClass);
}
}
} catch (CoreException | IOException exc) {
exc.printStackTrace();
}
}
return tempClass;
}
private class JavaBuildListener implements IResourceChangeListener {
@Override
public void resourceChanged(IResourceChangeEvent anEvent) {
if (anEvent.getType() == IResourceChangeEvent.POST_BUILD) {
if (checkForJavaClassOrProjectChange(anEvent.getDelta())) {
classCache.clear();
}
}
}
private boolean checkForJavaClassOrProjectChange(IResourceDelta aDelta) {
IResourceDelta[] tempChilds = aDelta.getAffectedChildren();
if (tempChilds != null && tempChilds.length > 0) {
for (IResourceDelta tempChild : tempChilds) {
boolean tempChange = checkForJavaClassOrProjectChange(tempChild);
if (tempChange) {
return tempChange;
}
}
} else {
IPath tempPath = aDelta.getFullPath();
if (tempPath != null) {
String tempFileExtension = tempPath.getFileExtension();
return ("java".equals(tempFileExtension) || "jar".equals(tempFileExtension) || "classpath"
.equals(tempFileExtension));
}
}
return false;
}
}
}