/*
* 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.thread;
import java.io.File;
import java.io.FileInputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Properties;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.MDC;
import org.hyperic.util.ArrayUtil;
/**
* A class which is able to spawn off multiple threads, each within their
* own classloader.
*/
public class MultiRunner {
public static final String PROP_CLONE_SPAWN_SLEEP = "clone.spawn.sleep";
public static final String PROP_CLONE_CLASSPATH = "clone.classpath";
public static final String PROP_CLONE_NUM = "clone.number";
public static final String PROP_CLONE_CLASS = "clone.class";
private Properties _props;
public MultiRunner(Properties p) {
_props = p;
}
private static class TargetRunnable implements Runnable {
private ClassLoader _loader;
private MultiRunnable _target;
private int _threadNo;
private Properties _props;
TargetRunnable(ClassLoader cl, MultiRunnable target, int threadNo,
Properties props)
{
_loader = cl;
_target = target;
_threadNo = threadNo;
_props = props;
}
public void run() {
try {
Thread.currentThread().setContextClassLoader(_loader);
_target.configure(_threadNo, _props);
_target.run();
} catch(Throwable e) {
e.printStackTrace();
}
}
}
private ClassLoader createThreadClassLoader() throws Exception {
String classPath = _props.getProperty(PROP_CLONE_CLASSPATH);
String[] split = classPath.split(":");
URL[] urls = new URL[split.length];
for (int i=0; i<split.length; i++) {
File f = new File(split[i].trim());
if (!f.canRead()) {
System.out.println("Can't read [" + f.getAbsolutePath() + "]");
}
urls[i] = f.toURL();
}
return new URLClassLoader(urls,
Thread.currentThread().getContextClassLoader());
}
private void startThread(int threadNo) throws Exception {
ClassLoader cl = createThreadClassLoader();
String className = _props.getProperty(PROP_CLONE_CLASS);
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(cl);
Class c = cl.loadClass(className);
MultiRunnable r = (MultiRunnable)c.newInstance();
Properties subProps = new Properties();
subProps.putAll(_props);
MDC.put("cloneId", "clone-" + threadNo);
Logger.getLogger(MultiRunner.class).info("Initializing log for clone-" + threadNo);
TargetRunnable tr = new TargetRunnable(cl, r, threadNo, subProps);
Thread t = new Thread(tr);
t.start();
} finally {
Thread.currentThread().setContextClassLoader(oldLoader);
}
}
public void runThreads() throws Exception {
String cloneSleepStr = _props.getProperty(PROP_CLONE_SPAWN_SLEEP);
long cloneSleep = Long.parseLong(cloneSleepStr);
String numClonesStr = _props.getProperty(PROP_CLONE_NUM);
int numClones = Integer.parseInt(numClonesStr);
for (int i=0; i< numClones; i++) {
startThread(i);
Thread.sleep(cloneSleep);
}
}
public static void main(String[] args) throws Exception {
Properties p = new Properties();
File in = new File(args[0]);
FileInputStream fis = null;
try {
fis = new FileInputStream(in);
p.load(fis);
} finally {
fis.close();
}
BasicConfigurator.configure();
PropertyConfigurator.configure(args[0]);
Logger.getLogger(MultiRunner.class).info("MultiRunner.class");
MultiRunner m = new MultiRunner(p);
m.runThreads();
}
}