Java tutorial
/* * NOTE: This copyright does *not* cover user programs that use HQ * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2004, 2005, 2006], Hyperic, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. This program is distributed * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ package org.hyperic.util; import java.io.File; import java.io.FilenameFilter; import java.net.URLClassLoader; import java.net.URL; import java.net.JarURLConnection; import java.net.MalformedURLException; import java.util.jar.Attributes; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class PluginLoader extends URLClassLoader { private static Log _log = LogFactory.getLog(PluginLoader.class.getName()); //XXX WAS 6.1 seems to have an issue with %20 private static final boolean ESCAPE_SPACES = !"false".equals(System.getProperty("PluginLoader.ESCAPE_SPACES")); private Map addedURLs = new HashMap(); private String pluginClassName = null; private String pluginName; private ThreadLocal<ClassLoader> previousClassLoader = new ThreadLocal<ClassLoader>(); private static String toFileURL(String file) { if (ESCAPE_SPACES) { file = StringUtil.replace(file, " ", "%20"); } return "file:" + file; } private static URL toJarURL(String file) throws MalformedURLException { return new URL("jar", "", toFileURL(file) + "!/"); } private static URL toURL(String file) throws MalformedURLException { return new URL(toFileURL(file)); } /* * if classname is a jar, try to configure the plugin using jar * attributes */ public static String getPluginMainClass(URL url) throws Exception { JarURLConnection jarConn = (JarURLConnection) url.openConnection(); Attributes attrs = jarConn.getMainAttributes(); String pluginName = attrs.getValue(Attributes.Name.MAIN_CLASS); return pluginName; } /* * allow each plugin to have their own classpath. */ public static PluginLoader create(String pluginName, ClassLoader parent) throws PluginLoaderException { String pluginClassName = null; URL[] classpath; if (pluginName.endsWith(".jar")) { ArrayList urls = new ArrayList(); try { URL jarUrl = toJarURL(pluginName); urls.add(jarUrl); //note-to-self // Get the plugin name from the jar pluginClassName = getPluginMainClass(jarUrl); } catch (Exception e) { String msg = "failed to configure plugin jar=" + pluginName; throw new PluginLoaderException(msg, e); } classpath = (URL[]) urls.toArray(new URL[0]); } else { classpath = new URL[0]; } PluginLoader loader = new PluginLoader(classpath, parent, pluginClassName); loader.pluginName = new File(pluginName).getName(); return loader; } public static ClassLoader getClassLoader() { return Thread.currentThread().getContextClassLoader(); } public static void resetClassLoader(Object obj) { ClassLoader cl = obj.getClass().getClassLoader(); //XXX: should probably be dealt with by the caller if (cl instanceof PluginLoader) { PluginLoader pl = (PluginLoader) cl; setClassLoader(pl.previousClassLoader.get()); pl.previousClassLoader.set(null); } } public static boolean setClassLoader(Object obj) { ClassLoader current = getClassLoader(); ClassLoader cl = obj.getClass().getClassLoader(); if (cl == current || !(cl instanceof PluginLoader)) { return false; //already set or not a PluginLoader } PluginLoader pl = (PluginLoader) cl; pl.previousClassLoader.set(current); setClassLoader(pl); return true; } public static void setClassLoader(ClassLoader loader) { Thread.currentThread().setContextClassLoader(loader); } public Class loadPlugin() throws ClassNotFoundException, PluginLoaderException { if (pluginClassName == null) { String msg = "No Main-Class attribute found in MANIFEST"; throw new PluginLoaderException(msg); } return loadClass(pluginClassName); } public Class loadPlugin(String name, byte[] bytecode, int len) { return defineClass(name, bytecode, 0, len); } public void addURL(String url) throws PluginLoaderException { addURL(new File(url)); } private static class ClassPathFilter implements FilenameFilter { private String start; private String end; private ClassPathFilter(String start, String end) { this.start = start; this.end = end; } public boolean accept(File file, String name) { return name.startsWith(this.start) && name.endsWith(this.end); } } private void logAddPath(File path, boolean isExpand) { if (_log.isDebugEnabled()) { if (isExpand) { String url = path.toString(); if (addedURLs.get(url) == Boolean.TRUE) { return; //only print once } _log.debug(this.pluginName + " expanding " + path + "..."); addedURLs.put(url, Boolean.TRUE); } else { if (path.canRead()) { _log.debug(this.pluginName + " += " + path); } else { _log.debug(this.pluginName + " -= " + path + ": Permission denied"); } } } } public static String[] expand(File file) { String name = file.getName(); int ix = name.indexOf("*"); //good enough for version matching if (ix == -1) { return null; } File dir = file.getParentFile(); if (!dir.isDirectory()) { return null; } //support: "repository/geronimo/jars/geronimo-management-*.jar" String start = name.substring(0, ix); String end = name.substring(ix + 1); return dir.list(new ClassPathFilter(start, end)); } public void addURL(File file) throws PluginLoaderException { boolean isExpand = false; String[] jars = null; if (!file.exists()) { jars = expand(file); if (jars == null) { return; } isExpand = true; logAddPath(file, true); file = file.getParentFile(); } if (isExpand || file.isDirectory()) { if (!isExpand) { boolean addedDir = addedURLs.get(file) == Boolean.TRUE; logAddPath(file, true); if (!addedDir) { addedURLs.put(file, Boolean.TRUE); //add the directory itself //must end with '/' (see URLClassLoader) try { super.addURL(toURL(file.toString() + "/")); } catch (Exception e) { throw new PluginLoaderException(e.getMessage()); } } jars = file.list(); } if (jars == null) { return; } for (int j = 0; j < jars.length; j++) { addURL(new File(file, jars[j])); } return; } if (!file.exists()) { return; } String url = file.toString(); if (addedURLs.get(url) == Boolean.TRUE) { return; } addedURLs.put(url, Boolean.TRUE); try { logAddPath(file, false); addURL(toURL(url)); } catch (Exception e) { throw new PluginLoaderException(e.getMessage()); } } public void addURLs(String[] urls) throws PluginLoaderException { for (int i = 0; i < urls.length; i++) { addURL(urls[i]); } } public void addURLs(List urls) throws PluginLoaderException { for (int i = 0; i < urls.size(); i++) { addURL((String) urls.get(i)); } } private PluginLoader(URL[] urls, ClassLoader parent, String name) { super(urls, parent); pluginClassName = name; previousClassLoader.set(getClassLoader()); } public String toString() { URL[] urls = getURLs(); String s = super.toString() + "/" + this.pluginName + "=["; for (int i = 0; i < urls.length; i++) { s += urls[i].getFile(); if (i < urls.length - 1) { s += ", "; } } s += "]"; return s; } //hook for plugins to avoid having to set //LD_LIBRARY_PATH, SHLIB_PATH, PATH, etc. //in order to find third-party native libs. protected String findLibrary(String libname) { String lib = System.getProperty("net.covalent.lib." + libname); if (lib != null) { return lib; } return super.findLibrary(libname); } }