package org.eclipse.vjet.eclipse.javatojs.ui.commands;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.osgi.util.ManifestElement;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
public class ClassloaderUtils {
private static final String ORG_ECLIPSE_VJET_ECLIPSE_JAVATOJS_UI = "org.eclipse.vjet.eclipse.javatojs.core";
private static volatile ClassLoaderRegistry m_registry = new ClassLoaderRegistry();
public enum ClassLoaderKey {
APPLICATION_EXPLORER("ApplicationExplorer"), DEFAULT("Default"), COMPONENT(
"Component"), WORKSPACE("Workspace"), WORKSPACECODEGEN(
"WorkspaceCodeGen"), WORKSPACEPLUSMEGAJAR(
"WorkspacePlusMegajar"), WIZARD("Wizard");
private String m_name;
ClassLoaderKey(String name) {
m_name = name;
}
public String getName() {
return m_name;
}
}
private static final class ClassLoaderRegistry {
private Map<ClassLoaderKey, VJETPluginClassloader> m_loaderMap = new HashMap<ClassLoaderKey, VJETPluginClassloader>();
VJETPluginClassloader wizardClassLoaderCache = null;
public void register(ClassLoaderKey key, VJETPluginClassloader cl) {
if (m_loaderMap.get(key) != null) {
throw new ClassLoaderRegistryException("Key already exists");
}
m_loaderMap.put(key, cl);
}
public VJETPluginClassloader get(Object key) {
if (ClassLoaderKey.WIZARD == key) {
if (m_loaderMap.get(key) != null) {
if (wizardClassLoaderCache == null) {
VJETPluginClassloader loader = m_loaderMap.get(key);
List<IJavaProject> javaProjectList = null;
try {
javaProjectList = WorkspaceUtil.getAllProjects();
} catch (JavaModelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
HashMap<String, String> projectMap = new HashMap<String, String>();
URL[] projectUrls = null;
try {
projectUrls = ClassloaderUtils
.getProjectDependencyUrls(javaProjectList,
null, projectMap);
} catch (JavaModelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
URL[] currentUrlList = loader.getURLs();
Set<URL> currentUrlSet = new HashSet<URL>(Arrays
.asList(currentUrlList));
for (URL url : projectUrls) {
if (currentUrlSet.contains(url) == false) {
try {
loader.addWorkspaceUrl(url);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
wizardClassLoaderCache = loader;
}
return wizardClassLoaderCache;
}
}
return m_loaderMap.get(key);
}
public void clear() {
m_loaderMap.clear();
}
public void remove(ClassLoaderKey key) {
if (!m_loaderMap.containsKey(key)) {
return;
}
m_loaderMap.remove(key);
}
}
private static class ClassLoaderRegistryException extends RuntimeException {
public ClassLoaderRegistryException() {
super();
}
public ClassLoaderRegistryException(String message) {
super(message);
}
public ClassLoaderRegistryException(String message, Throwable cause) {
super(message, cause);
}
public ClassLoaderRegistryException(Throwable cause) {
super(cause);
}
}
public static Object getWorkspaceObject(
String workspaceClassNameWithPackage,
IProject... additionalProjectList) {
if (additionalProjectList.length != 0) {
addProjectsToClassLoader(additionalProjectList);
}
VJETPluginClassloader classLoader = getDefaultClassLoader();
return getWorkspaceObject(workspaceClassNameWithPackage, classLoader);
}
public static URL[] getProjectDependencyUrls(
List<IJavaProject> javaProjectList, List<URL> currentUrlList,
HashMap<String, String> projectMap) throws JavaModelException,
MalformedURLException {
List<URL> projectDependencyUrlList = currentUrlList;
if (projectDependencyUrlList == null) {
projectDependencyUrlList = new ArrayList<URL>();
}
for (IJavaProject project : javaProjectList) {
if (projectMap.containsKey(project.getElementName()) == true) {
continue;
} else {
projectMap.put(project.getElementName(), project
.getElementName());
}
// Add the dependencies to the URL list
IClasspathEntry[] entries;
entries = project.getResolvedClasspath(true);
for (IClasspathEntry entry : entries) {
IPath path = entry.getPath();
File f = path.toFile();
URL entryUrl;
entryUrl = f.toURL();
switch (entry.getEntryKind()) {
case IClasspathEntry.CPE_LIBRARY:
if (projectDependencyUrlList.contains(entryUrl) == false) {
projectDependencyUrlList.add(entryUrl);
}
break;
case IClasspathEntry.CPE_PROJECT:
List<IJavaProject> subjavaProjectList = new ArrayList<IJavaProject>();
IResource subResource = ResourcesPlugin.getWorkspace()
.getRoot().findMember(entry.getPath());
if (subResource == null) {
String projectName = entry.getPath().toString();
String parentProjectName = project.getElementName();
// throw new EclipseProjectNotFoundException(
// projectName,
// MessageFormat
// .format(
// "The dependent project {0} of project {1} is not available.\nPlease update your workspace to include this project",
// projectName, parentProjectName));
}
if (subResource.getType() == IResource.PROJECT) {
IProject subProject = (IProject) subResource;
IJavaProject subJavaProject = JavaCore
.create(subProject);
if (subJavaProject != null && subJavaProject.exists()) {
subjavaProjectList.add(subJavaProject);
// Recursively call our selves to populate the
// project
// dependency's for the sub projects.
getProjectDependencyUrls(subjavaProjectList,
projectDependencyUrlList, projectMap);
}
}
break;
default:
break;
}
}
IPath path = project.getOutputLocation();
IPath projectResourceLocation = project.getResource().getLocation();
File projectFilePath = projectResourceLocation.append(
path.removeFirstSegments(1)).toFile();
URL projectOutputUrl;
projectOutputUrl = projectFilePath.toURL();
if (projectDependencyUrlList.contains(projectOutputUrl) == false) {
projectDependencyUrlList.add(projectOutputUrl);
}
}
URL[] arrayList = new URL[projectDependencyUrlList.size()];
URL[] returnURLArray = projectDependencyUrlList.toArray(arrayList);
return returnURLArray;
}
public static VJETPluginClassloader getDefaultClassLoader() {
return findClassLoaderByKey(ClassLoaderKey.DEFAULT);
}
private static VJETPluginClassloader findClassLoaderByKey(ClassLoaderKey key) {
synchronized (m_registry) {
VJETPluginClassloader cl = m_registry.get(key);
if (cl == null) {
// clearMbServer();
cl = createClassLoader(key);
m_registry.register(key, cl);
}
return cl;
}
}
private static VJETPluginClassloader createClassLoader(ClassLoaderKey key) {
try {
// IV4ClasspathProvider classpathProvider = getClasspathProvider();
URL[] classloaderUrls = null;
// if (classpathProvider != null) {
// classloaderUrls = classpathProvider.getUrls();
// }
List<String> classPath = new ArrayList<String>();
Set<String> visitedBundles = new HashSet<String>();
Bundle bundle = Platform.getBundle(ORG_ECLIPSE_VJET_ECLIPSE_JAVATOJS_UI);
visitedBundles.add(ORG_ECLIPSE_VJET_ECLIPSE_JAVATOJS_UI);
extractClassPath(bundle, classPath, visitedBundles);
List<URL> classList = new ArrayList<URL>();
for(String path: classPath){
classList.add(new File(path).toURL());
}
classloaderUrls = classList.toArray(new URL[classList.size()]);
return createEclipseClassLoader(classloaderUrls);
// } catch (JavaModelException javaModelException) {
//// MessageUtils
//// .displayError(
//// "Dynamic Code Generation Error:JAVA MODEL EXCEPTION",
//// javaModelException.getMessage(),
//// javaModelException);
//
// return null;
} catch (Exception exception) {
// MessageUtils.displayError("Dynamic Code Generation Error:EXCEPTION",
// exception.getMessage(), exception);
}
return null;
}
@SuppressWarnings("unchecked")
private static void extractClassPath(
Bundle bundle, List<String> classPath, Set<String> visitedBundles) {
String baseLoc = getLocation(bundle);
Dictionary<String, String> dic = bundle.getHeaders();
if(baseLoc.endsWith("jar")){
classPath.add(baseLoc);
}
else {// DEV MODE ONLY CODE
classPath.add(baseLoc + File.separatorChar + "bin");
try {
ManifestElement[] cp = ManifestElement.parseHeader(
Constants.BUNDLE_CLASSPATH, dic.get(Constants.BUNDLE_CLASSPATH));
for (int iter = 0; cp != null && iter < cp.length; iter++) {
classPath.add(baseLoc + File.separatorChar + cp[iter].getValue());
}
} catch (BundleException be) {
// TODO: log this error
// skip this entries...
be.printStackTrace();
}
}
//search dependent bundle
try {
ManifestElement[] mfEls = ManifestElement.parseHeader(
Constants.REQUIRE_BUNDLE, (String) dic
.get(Constants.REQUIRE_BUNDLE));
for (int iter = 0; mfEls != null && iter < mfEls.length; iter++) {
String bundleName = mfEls[iter].getValue();
if (!visitedBundles.contains(bundleName)) {
Bundle bundle2 = Platform.getBundle(bundleName);
if(bundle2!=null){ // HANDLE runtime bundles /fragments which are not needed
visitedBundles.add(bundleName);
extractClassPath(bundle2, classPath, visitedBundles);
}
}
}
} catch (BundleException be) {
// TODO: log this error
// skip this entries...
}
}
private static String getLocation(Bundle bundle) {
String location = bundle.getLocation();
location = location.substring(location.indexOf("@") + 1);
// add by patrick for 3.5 compatibility
int tempIndex = location.indexOf("reference:file:");
if (tempIndex > -1) {
location = location.substring(location.indexOf("file:") + 5);
}
// end add
if (!new File(location).isAbsolute()) {
location = new File(Platform.getInstallLocation().getURL()
.getFile(), location).getAbsolutePath();
}
return location;
}
private static VJETPluginClassloader createEclipseClassLoader(URL[] urls) {
// Get the project list
ClassLoader eclipse = VJETPluginClassloader.class.getClassLoader();
VJETPluginClassloader classLoader = null;
try {
classLoader = new VJETPluginClassloader(urls, eclipse);
// } catch (InvalidProjectException invalidProjectException) {
//// String detailMessage = MessageFormat.format(
//// "Project {0} is invalid", invalidProjectException
//// .getProjectName());
//// MessageUtils.displayError("Dynamic Code Generation Error",
//// invalidProjectException.getMessage(), invalidProjectException);
// return null;
// } catch (EclipseProjectNotFoundException codeGenProjectException) {
//// String detailMessage = MessageFormat.format(
//// "Project {0} is not in the current Workspace, please add.",
//// codeGenProjectException.getProjectName());
//// MessageUtils.displayError("Dynamic Code Generation Error",
//// codeGenProjectException.getMessage(), codeGenProjectException);
// return null;
} catch (MalformedURLException malformedUrlException) {
String detailMessage = "The Url is malformed please ensure all urls are valid.";
// MessageUtils.displayError("Dynamic Code Generation Error",
// malformedUrlException.getMessage(), malformedUrlException);
return null;
} catch (IOException ioException) {
String detailMessage = "An io exception has occured. The class loader most likely could not load one of the dependent jar files.";
// MessageUtils.displayError("Dynamic Code Generation Error",
// ioException.getMessage(), ioException);
}
return classLoader;
}
private static Object getWorkspaceObject(
String workspaceClassNameWithPackage,
VJETPluginClassloader classLoader) {
if (classLoader == null) {
return null;
}
// Attempt to load the class
Class codegenClass = null;
try {
codegenClass = classLoader.loadClass(workspaceClassNameWithPackage);
} catch (ClassNotFoundException e) {
// logger.error(e.getMessage(), e);
throw new RuntimeException("ClassNotFoundException:"
+ workspaceClassNameWithPackage, e);
}
// Attempt to intanciate the class
Object targetObject = null;
try {
targetObject = codegenClass.newInstance();
} catch (Exception e) {
// logger.error(e.getMessage(), e);
return null;
}
return targetObject;
}
private static void addProjectsToClassLoader(
IProject[] additionalProjectList) {
// TODO Auto-generated method stub
}
public static Object getWorkspaceObject(
String workspaceClassNameWithPackage, ClassLoaderKey classLoaderKey) {
VJETPluginClassloader classLoader = findClassLoaderByKey(classLoaderKey);
return getWorkspaceObject(workspaceClassNameWithPackage, classLoader);
}
}