/*
* 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.hq.product.util;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.net.URLClassLoader;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Iterator;
import java.util.Properties;
import org.apache.log4j.PropertyConfigurator;
import org.hyperic.hq.product.ProductPlugin;
import org.hyperic.hq.product.ProductPluginManager;
import org.hyperic.util.PluginLoader;
/**
* Run the main method for a plugin class.
* Example:
* java -jar pdk/lib/hq-pdk.jar apache ApacheServerDetector
*/
//cut-n-pasted-n-chopped from sigar.cmd.Runner class
public class PluginMain {
private static final String DEFAULT_PACKAGE =
"org.hyperic.hq.plugin";
private static URL jarURL(String jar) throws Exception {
return new URL("jar", null, "file:" + jar + "!/");
}
private static URL[] getLibJars(String dir) throws Exception {
File[] jars = new File(dir).listFiles(new FileFilter() {
public boolean accept(File file) {
return file.getName().endsWith(".jar");
}
});
if (jars == null) {
return new URL[0];
}
URL[] urls = new URL[jars.length];
for (int i=0; i<jars.length; i++) {
urls[i] = jarURL(jars[i].getAbsolutePath());
}
return urls;
}
private static void addVersionFile(String pdkDir) throws Exception {
//Add URL for agent lib dir containing hq-version.properties for -v option
File versionProperties =
new File(pdkDir, "../lib");
URL versionProps = versionProperties.toURI().toURL();
addURLs(new URL[] {versionProps});
}
private static URLClassLoader getLoader() {
return (URLClassLoader)Thread.currentThread().getContextClassLoader();
}
private static String getPdkDir() {
URL[] urls = getLoader().getURLs();
for (int i=0; i<urls.length; i++) {
String url = urls[i].getFile();
if (!url.contains(PluginDumper.PRODUCT_JAR)) {
continue;
}
url = URLDecoder.decode(url); //"%20" -> " "
//strip lib/hq-pdk.jar
return new File(url).getParentFile().getParent();
}
return "pdk";
}
private static void addURLs(URL[] jars) throws Exception {
URLClassLoader loader = getLoader();
//bypass protected access.
Method addURL =
URLClassLoader.class.getDeclaredMethod("addURL",
new Class[] {
URL.class
});
addURL.setAccessible(true); //pound sand.
for (int i=0; i<jars.length; i++) {
addURL.invoke(loader, new Object[] { jars[i] });
}
}
private static void addJarDir(String dir) throws Exception {
URL[] jars = getLibJars(dir);
addURLs(jars);
}
private static Class getPluginClass(PluginDumper pd,
String plugin,
String className) throws Exception {
pd.init();
ProductPlugin productPlugin = pd.ppm.getProductPlugin(plugin);
String packageName = productPlugin.getPluginProperty("package");
if (packageName == null) {
packageName = DEFAULT_PACKAGE + "." + plugin;
}
String mainClass = packageName + "." + className;
PluginLoader.setClassLoader(productPlugin);
try {
return Class.forName(mainClass, true,
productPlugin.getClass().getClassLoader());
} catch (ClassNotFoundException e) {
System.out.println("Invalid ClassName: " + mainClass);
return null;
} finally {
PluginLoader.resetClassLoader(productPlugin);
}
}
private static void runMain(PluginDumper pd,
String[] args) throws Exception {
int offset;
ProductPlugin productPlugin = null;
String plugin, className=null, mainClass=null;
final String usage =
"Usage: PluginMain plugin ClassName";
if (args.length < 1) {
throw new IllegalArgumentException(usage);
}
plugin = args[0];
if (plugin.indexOf(".") != -1) {
//example:
//java -jar pdk/lib/hq-pdk.jar \
//org.hyperic.hq.product.URLMetric https://localhost/
mainClass = plugin;
plugin = null;
offset = 1;
}
else {
if (args.length < 2) {
throw new IllegalArgumentException(usage);
}
//example:
//java -jar pdk/lib/hq-pdk.jar \
//apache ApacheServerDetector
className = args[1];
offset = 2;
}
String[] pargs = new String[args.length - offset];
System.arraycopy(args, offset, pargs, 0, args.length-offset);
Class cmd = null;
if (plugin != null) {
cmd = getPluginClass(pd, plugin, className);
if (cmd == null) {
return;
}
productPlugin = pd.ppm.getProductPlugin(plugin);
}
else {
try {
cmd = Class.forName(mainClass);
} catch (ClassNotFoundException e) {
System.out.println("Invalid ClassName: " + mainClass);
return;
}
}
Method main = cmd.getMethod("main",
new Class[] {
String[].class
});
if (productPlugin != null) {
PluginLoader.setClassLoader(productPlugin);
}
try {
main.invoke(null, new Object[] { pargs });
} catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
if (t instanceof NoClassDefFoundError) {
System.out.println("Class Not Found: " +
t.getMessage());
}
else {
t.printStackTrace();
}
}
finally {
if (productPlugin != null) {
PluginLoader.resetClassLoader(productPlugin);
}
}
}
private static final String[][] LOG_PROPS = {
{ "log4j.appender.R", "org.apache.log4j.ConsoleAppender" },
{ "log4j.appender.R.layout.ConversionPattern", "%-5p [%t] [%c{1}] %m%n" },
{ "log4j.appender.R.layout", "org.apache.log4j.PatternLayout" }
};
private static void configureLogging(String pdkDir, String level) {
if (new File(level).exists()) {
PropertyConfigurator.configure(level);
return;
}
Properties props = new Properties();
Properties agentProps = new Properties();
//pickup categories from from agent.properties
File agentProperties =
new File(pdkDir, "../../../conf/agent.properties");
if (agentProperties.exists()) {
InputStream is = null;
try {
is = new FileInputStream(agentProperties);
agentProps.load(is);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try { is.close(); } catch (Exception e) {}
}
}
}
for (Iterator it = agentProps.keySet().iterator();
it.hasNext();)
{
String key = (String)it.next();
if (key.startsWith("log4j.logger.") ||
key.startsWith("log4j.category."))
{
props.setProperty(key, agentProps.getProperty(key));
}
}
props.setProperty("log4j.rootLogger", level.toUpperCase() + ", R");
for (int i=0; i<LOG_PROPS.length; i++) {
props.setProperty(LOG_PROPS[i][0], LOG_PROPS[i][1]);
}
props.putAll(System.getProperties());
PropertyConfigurator.configure(props);
}
public static void main(String[] args) throws Exception {
String pdkDir =
System.getProperty(ProductPluginManager.PROP_PDK_DIR, getPdkDir());
File tmpDir = new File(new File(pdkDir).getParentFile(), "tmp");
//point the the agent tmp dir which gets cleaned out everytime
//the agent is started. a must for windows where the files will
//not get deleted because they are still open.
if (tmpDir.exists() && tmpDir.canWrite()) {
System.setProperty("java.io.tmpdir", tmpDir.toString());
}
String pdkLib = pdkDir + File.separator + "lib";
String logLevel = System.getProperty("log", "error");
//bleh, make sure we get log level right.
for (int i=0; i<args.length; i++) {
if (args[i].startsWith("-Dlog=")) {
logLevel = args[i].substring(6);
}
}
addJarDir(pdkLib);
addVersionFile(pdkDir);
System.setProperty("org.hyperic.sigar.path", pdkLib);
ProductPluginManager.setPdkDir(pdkDir);
configureLogging(pdkDir, logLevel);
PluginDumper pd = new PluginDumper(args);
//XXX this is hackish, but dwim is more important
if (!pd.config.hasSwitches) {
runMain(pd, pd.config.args);
}
else {
pd.init();
pd.invoke();
pd.shutdown();
}
System.exit(0);
}
}