Java tutorial
/** * This file is part of the Kompics P2P Framework. * * Copyright (C) 2009 Swedish Institute of Computer Science (SICS) * Copyright (C) 2009 Royal Institute of Technology (KTH) * * Kompics is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * 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 se.sics.kompics.p2p.experiment.dsl; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.PrintStream; import java.io.Serializable; import java.math.BigInteger; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays; import java.util.Enumeration; import java.util.HashSet; import java.util.LinkedList; import java.util.Properties; import java.util.Random; import java.util.TimeZone; import java.util.jar.JarEntry; import java.util.jar.JarFile; import javassist.CannotCompileException; import javassist.ClassPool; import javassist.CtClass; import javassist.Loader; import javassist.NotFoundException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import se.sics.kompics.ComponentDefinition; import se.sics.kompics.KompicsEvent; import se.sics.kompics.p2p.experiment.dsl.adaptor.ConcreteOperation; import se.sics.kompics.p2p.experiment.dsl.adaptor.Operation; import se.sics.kompics.p2p.experiment.dsl.adaptor.Operation1; import se.sics.kompics.p2p.experiment.dsl.adaptor.Operation2; import se.sics.kompics.p2p.experiment.dsl.adaptor.Operation3; import se.sics.kompics.p2p.experiment.dsl.adaptor.Operation4; import se.sics.kompics.p2p.experiment.dsl.adaptor.Operation5; import se.sics.kompics.p2p.experiment.dsl.adaptor.OperationGenerator; import se.sics.kompics.p2p.experiment.dsl.distribution.BigIntegerExponentialDistribution; import se.sics.kompics.p2p.experiment.dsl.distribution.BigIntegerNormalDistribution; import se.sics.kompics.p2p.experiment.dsl.distribution.BigIntegerUniformDistribution; import se.sics.kompics.p2p.experiment.dsl.distribution.ConstantDistribution; import se.sics.kompics.p2p.experiment.dsl.distribution.Distribution; import se.sics.kompics.p2p.experiment.dsl.distribution.DoubleExponentialDistribution; import se.sics.kompics.p2p.experiment.dsl.distribution.DoubleNormalDistribution; import se.sics.kompics.p2p.experiment.dsl.distribution.DoubleUniformDistribution; import se.sics.kompics.p2p.experiment.dsl.distribution.LongExponentialDistribution; import se.sics.kompics.p2p.experiment.dsl.distribution.LongNormalDistribution; import se.sics.kompics.p2p.experiment.dsl.distribution.LongUniformDistribution; import se.sics.kompics.p2p.experiment.dsl.events.SimulationTerminatedEvent; import se.sics.kompics.p2p.experiment.dsl.events.SimulatorEvent; import se.sics.kompics.p2p.experiment.dsl.events.StochasticProcessEvent; import se.sics.kompics.p2p.experiment.dsl.events.StochasticProcessStartEvent; import se.sics.kompics.p2p.experiment.dsl.events.StochasticProcessTerminatedEvent; import se.sics.kompics.p2p.experiment.dsl.events.TakeSnapshot; import se.sics.kompics.p2p.experiment.dsl.events.TakeSnapshotEvent; import se.sics.kompics.simulation.TimeInterceptor; /** * The <code>SimulationScenario</code> class. * * @author Cosmin Arad <cosmin@sics.se> * @version $Id$ */ public abstract class SimulationScenario implements Serializable { /** The Constant serialVersionUID. */ private static final long serialVersionUID = 5278102582431240537L; /** The logger. */ private static Logger logger = LoggerFactory.getLogger("se.sics.kompics.simulation.CodeInstrumenter"); /** The random. */ private final Random random; /** The processes. */ private final LinkedList<StochasticProcess> processes; /** The process count. */ private int processCount; /** The terminated event. */ private SimulationTerminatedEvent terminatedEvent; /** * Instantiates a new simulation scenario. */ public SimulationScenario() { this.random = new Random(); this.processes = new LinkedList<StochasticProcess>(); this.processCount = 0; } /** * Sets the seed. * * @param seed * the new seed */ public void setSeed(long seed) { random.setSeed(seed); } /** * Gets the random. * * @return the random */ public Random getRandom() { return random; } /** * The <code>StochasticProcess</code> class. * * @author Cosmin Arad <cosmin@sics.se> * @version $Id$ */ protected abstract class StochasticProcess implements Serializable { /** The Constant serialVersionUID. */ private static final long serialVersionUID = -6303689523381305745L; /** The relative start time. */ private boolean relativeStartTime; /** The start time. */ private long startTime; /** The start event. */ private StochasticProcessStartEvent startEvent; /** The terminate event. */ private StochasticProcessTerminatedEvent terminateEvent; /** The stochastic event. */ private StochasticProcessEvent stochasticEvent; /** The inter arrival time. */ private Distribution<Long> interArrivalTime = null; /** The generators. */ private LinkedList<OperationGenerator> generators = new LinkedList<OperationGenerator>(); /** The name. */ private final String name; /** The started. */ private boolean started = false; /** * Instantiates a new stochastic process. * * @param name * the name */ protected StochasticProcess(String name) { this.name = name; processCount++; } /** * Instantiates a new stochastic process. */ protected StochasticProcess() { processCount++; this.name = "Process" + processCount; } /** * Event inter arrival time. * * @param interArrivalTime * the inter arrival time */ protected final void eventInterArrivalTime(Distribution<Long> interArrivalTime) { this.interArrivalTime = interArrivalTime; } /** * Raise. * * @param count * the count * @param op * the op */ protected final <E extends KompicsEvent> void raise(int count, Operation<E> op) { if (count <= 0) { throw new RuntimeException("Number of raised events must be strictly positive"); } OperationGenerator generator = new OperationGenerator( new ConcreteOperation<E, Number, Number, Number, Number, Number>(op), count); generators.add(generator); } /** * Raise. * * @param count * the count * @param op1 * the op1 * @param d1 * the d1 */ protected final <E extends KompicsEvent, P1 extends Number> void raise(int count, Operation1<E, P1> op1, Distribution<P1> d1) { if (count <= 0) { throw new RuntimeException("Number of raised events must be strictly positive"); } OperationGenerator generator = new OperationGenerator( new ConcreteOperation<E, P1, Number, Number, Number, Number>(op1, d1), count); generators.add(generator); } /** * Raise. * * @param count * the count * @param op2 * the op2 * @param d1 * the d1 * @param d2 * the d2 */ protected final <E extends KompicsEvent, P1 extends Number, P2 extends Number> void raise(int count, Operation2<E, P1, P2> op2, Distribution<P1> d1, Distribution<P2> d2) { if (count <= 0) { throw new RuntimeException("Number of raised events must be strictly positive"); } OperationGenerator generator = new OperationGenerator( new ConcreteOperation<E, P1, P2, Number, Number, Number>(op2, d1, d2), count); generators.add(generator); } /** * Raise. * * @param count * the count * @param op3 * the op3 * @param d1 * the d1 * @param d2 * the d2 * @param d3 * the d3 */ protected final <E extends KompicsEvent, P1 extends Number, P2 extends Number, P3 extends Number> void raise( int count, Operation3<E, P1, P2, P3> op3, Distribution<P1> d1, Distribution<P2> d2, Distribution<P3> d3) { if (count <= 0) { throw new RuntimeException("Number of raised events must be strictly positive"); } OperationGenerator generator = new OperationGenerator( new ConcreteOperation<E, P1, P2, P3, Number, Number>(op3, d1, d2, d3), count); generators.add(generator); } /** * Raise. * * @param count * the count * @param op4 * the op4 * @param d1 * the d1 * @param d2 * the d2 * @param d3 * the d3 * @param d4 * the d4 */ protected final <E extends KompicsEvent, P1 extends Number, P2 extends Number, P3 extends Number, P4 extends Number, P5 extends Number> void raise( int count, Operation4<E, P1, P2, P3, P4> op4, Distribution<P1> d1, Distribution<P2> d2, Distribution<P3> d3, Distribution<P4> d4) { if (count <= 0) { throw new RuntimeException("Number of raised events must be strictly positive"); } OperationGenerator generator = new OperationGenerator( new ConcreteOperation<E, P1, P2, P3, P4, Number>(op4, d1, d2, d3, d4), count); generators.add(generator); } /** * Raise. * * @param count * the count * @param op5 * the op5 * @param d1 * the d1 * @param d2 * the d2 * @param d3 * the d3 * @param d4 * the d4 * @param d5 * the d5 */ protected final <E extends KompicsEvent, P1 extends Number, P2 extends Number, P3 extends Number, P4 extends Number, P5 extends Number> void raise( int count, Operation5<E, P1, P2, P3, P4, P5> op5, Distribution<P1> d1, Distribution<P2> d2, Distribution<P3> d3, Distribution<P4> d4, Distribution<P5> d5) { if (count <= 0) { throw new RuntimeException("Number of raised events must be strictly positive"); } OperationGenerator generator = new OperationGenerator( new ConcreteOperation<E, P1, P2, P3, P4, P5>(op5, d1, d2, d3, d4, d5), count); generators.add(generator); } /** * Start. */ public final void start() { relativeStartTime = false; startTime = 0; started = true; terminateEvent = new StochasticProcessTerminatedEvent(0, new LinkedList<StochasticProcessStartEvent>(), name); stochasticEvent = new StochasticProcessEvent(0, interArrivalTime, terminateEvent, generators, name); startEvent = new StochasticProcessStartEvent(startTime, new LinkedList<StochasticProcessStartEvent>(), stochasticEvent, 0, name); processes.remove(this); processes.add(this); } /** * Start at. * * @param time * the time */ public final void startAt(long time) { relativeStartTime = false; startTime = time; started = true; terminateEvent = new StochasticProcessTerminatedEvent(0, new LinkedList<StochasticProcessStartEvent>(), name); stochasticEvent = new StochasticProcessEvent(0, interArrivalTime, terminateEvent, generators, name); startEvent = new StochasticProcessStartEvent(startTime, new LinkedList<StochasticProcessStartEvent>(), stochasticEvent, 0, name); processes.remove(this); processes.add(this); } /** * Start at same time with. * * @param process * the process */ public final void startAtSameTimeWith(StochasticProcess process) { relativeStartTime = true; started = true; startTime = 0; terminateEvent = new StochasticProcessTerminatedEvent(0, new LinkedList<StochasticProcessStartEvent>(), name); stochasticEvent = new StochasticProcessEvent(0, interArrivalTime, terminateEvent, generators, name); startEvent = new StochasticProcessStartEvent(startTime, new LinkedList<StochasticProcessStartEvent>(), stochasticEvent, 0, name); // we hook this process' start event to the referenced process' // list of start events if (!process.started) { throw new RuntimeException(process.name + " not started"); } process.startEvent.getStartEvents().add(startEvent); processes.remove(this); processes.add(this); } /** * Start after start of. * * @param delay * the delay * @param process * the process */ public final void startAfterStartOf(long delay, StochasticProcess process) { relativeStartTime = true; started = true; startTime = delay; terminateEvent = new StochasticProcessTerminatedEvent(0, new LinkedList<StochasticProcessStartEvent>(), name); stochasticEvent = new StochasticProcessEvent(0, interArrivalTime, terminateEvent, generators, name); startEvent = new StochasticProcessStartEvent(startTime, new LinkedList<StochasticProcessStartEvent>(), stochasticEvent, 0, name); // we hook this process' start event to the referenced process' // list of start events if (!process.started) { throw new RuntimeException(process.name + " not started"); } process.startEvent.getStartEvents().add(startEvent); processes.remove(this); processes.add(this); } /** * Start after termination of. * * @param delay * the delay * @param process * the process */ public final void startAfterTerminationOf(long delay, StochasticProcess... process) { relativeStartTime = true; started = true; startTime = delay; terminateEvent = new StochasticProcessTerminatedEvent(0, new LinkedList<StochasticProcessStartEvent>(), name); stochasticEvent = new StochasticProcessEvent(0, interArrivalTime, terminateEvent, generators, name); startEvent = new StochasticProcessStartEvent(startTime, new LinkedList<StochasticProcessStartEvent>(), stochasticEvent, process.length, name); // we hook this process' start event to the referenced process' // list of start events HashSet<StochasticProcess> procs = new HashSet<StochasticProcess>(Arrays.asList(process)); for (StochasticProcess stochasticProcess : procs) { if (!stochasticProcess.started) { throw new RuntimeException(stochasticProcess.name + " not started"); } stochasticProcess.terminateEvent.getStartEvents().add(startEvent); } processes.remove(this); processes.add(this); } } /** * Terminate at. * * @param time * the time */ protected final void terminateAt(long time) { SimulationTerminatedEvent terminationEvent = new SimulationTerminatedEvent(time, 0, false); terminatedEvent = terminationEvent; } /** * Terminate after termination of. * * @param delay * the delay * @param process * the process */ protected final void terminateAfterTerminationOf(long delay, StochasticProcess... process) { HashSet<StochasticProcess> procs = new HashSet<StochasticProcess>(Arrays.asList(process)); SimulationTerminatedEvent terminationEvent = new SimulationTerminatedEvent(delay, procs.size(), true); terminatedEvent = terminationEvent; for (StochasticProcess stochasticProcess : procs) { if (!stochasticProcess.started) { throw new RuntimeException(stochasticProcess.name + " not started"); } stochasticProcess.terminateEvent.setTerminationEvent(terminationEvent); } } /** * Constant. * * @param value * the value * * @return the distribution< double> */ protected final Distribution<Double> constant(double value) { return new ConstantDistribution<Double>(Double.class, value); } /** * Constant. * * @param value * the value * * @return the distribution< long> */ protected final Distribution<Long> constant(long value) { return new ConstantDistribution<Long>(Long.class, value); } /** * Constant. * * @param value * the value * * @return the distribution< big integer> */ protected final Distribution<BigInteger> constant(BigInteger value) { return new ConstantDistribution<BigInteger>(BigInteger.class, value); } /** * Uniform. * * @param min * the min * @param max * the max * * @return the distribution< double> */ protected final Distribution<Double> uniform(double min, double max) { return new DoubleUniformDistribution(min, max, random); } /** * Uniform. * * @param min * the min * @param max * the max * * @return the distribution< long> */ protected final Distribution<Long> uniform(long min, long max) { return new LongUniformDistribution(min, max, random); } /** * Uniform. * * @param min * the min * @param max * the max * * @return the distribution< big integer> */ protected final Distribution<BigInteger> uniform(BigInteger min, BigInteger max) { return new BigIntegerUniformDistribution(min, max, random); } /** * Uniform. * * @param numBits * the num bits * * @return the distribution< big integer> */ protected final Distribution<BigInteger> uniform(int numBits) { return new BigIntegerUniformDistribution(numBits, random); } /** * Exponential. * * @param mean * the mean * * @return the distribution< double> */ protected final Distribution<Double> exponential(double mean) { return new DoubleExponentialDistribution(mean, random); } /** * Exponential. * * @param mean * the mean * * @return the distribution< long> */ protected final Distribution<Long> exponential(long mean) { return new LongExponentialDistribution(mean, random); } /** * Exponential. * * @param mean * the mean * * @return the distribution< big integer> */ protected final Distribution<BigInteger> exponential(BigInteger mean) { return new BigIntegerExponentialDistribution(mean, random); } /** * Normal. * * @param mean * the mean * @param variance * the variance * * @return the distribution< double> */ protected final Distribution<Double> normal(double mean, double variance) { return new DoubleNormalDistribution(mean, variance, random); } /** * Normal. * * @param mean * the mean * @param variance * the variance * * @return the distribution< long> */ protected final Distribution<Long> normal(long mean, long variance) { return new LongNormalDistribution(mean, variance, random); } /** * Normal. * * @param mean * the mean * @param variance * the variance * * @return the distribution< big integer> */ protected final Distribution<BigInteger> normal(BigInteger mean, BigInteger variance) { return new BigIntegerNormalDistribution(mean, variance, random); } /** * The <code>Snapshot</code> class. * * @author Cosmin Arad <cosmin@sics.se> * @version $Id$ */ protected final static class Snapshot { /** The take snapshot event. */ private final TakeSnapshot takeSnapshotEvent; /** * Instantiates a new snapshot. * * @param takeSnapshotEvent * the take snapshot event */ public Snapshot(TakeSnapshot takeSnapshotEvent) { this.takeSnapshotEvent = takeSnapshotEvent; } /** * Take after termination of. * * @param delay * the delay * @param process * the process */ public void takeAfterTerminationOf(long delay, StochasticProcess... process) { HashSet<StochasticProcess> procs = new HashSet<StochasticProcess>(Arrays.asList(process)); TakeSnapshotEvent snapshotEvent = new TakeSnapshotEvent(delay, takeSnapshotEvent, procs.size()); for (StochasticProcess stochasticProcess : procs) { stochasticProcess.terminateEvent.setSnapshotEvent(snapshotEvent); } } } /** * Snapshot. * * @param takeSnapshotEvent * the take snapshot event * * @return the snapshot */ protected final Snapshot snapshot(TakeSnapshot takeSnapshotEvent) { return new Snapshot(takeSnapshotEvent); } /** * Executes simulation. * * @param main * the main */ public final void simulate(Class<? extends ComponentDefinition> main) { store(); try { Loader cl = AccessController.doPrivileged(new PrivilegedAction<Loader>() { @Override public Loader run() { return new Loader(); } }); cl.addTranslator(ClassPool.getDefault(), new TimeInterceptor(null)); Thread.currentThread().setContextClassLoader(cl); TimeZone.setDefault(TimeZone.getTimeZone("GMT")); cl.run(main.getCanonicalName(), null); } catch (Throwable e) { throw new RuntimeException("Exception caught during simulation", e); } } /** * Transform. * * @param main * the main * @param directory * the directory */ public final void transform(Class<? extends ComponentDefinition> main, String directory) { Properties p = new Properties(); File dir = null; File file = null; try { dir = new File(directory); dir.mkdirs(); dir.setWritable(true); file = File.createTempFile("scenario", ".bin", dir); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file)); oos.writeObject(this); oos.flush(); oos.close(); System.setProperty("scenario", file.getAbsolutePath()); p.setProperty("scenario", file.getAbsolutePath()); p.store(new FileOutputStream(file.getAbsolutePath() + ".properties"), null); } catch (IOException e) { e.printStackTrace(); } try { Loader cl = AccessController.doPrivileged(new PrivilegedAction<Loader>() { @Override public Loader run() { return new Loader(); } }); cl.addTranslator(ClassPool.getDefault(), new TimeInterceptor(dir)); Thread.currentThread().setContextClassLoader(cl); TimeZone.setDefault(TimeZone.getTimeZone("GMT")); cl.run(main.getCanonicalName(), null); } catch (Throwable e) { throw new RuntimeException("Exception caught during simulation", e); } } /** * Execute. * * @param main * the main */ public final void execute(Class<? extends ComponentDefinition> main) { store(); try { Loader cl = AccessController.doPrivileged(new PrivilegedAction<Loader>() { @Override public Loader run() { return new Loader(); } }); Thread.currentThread().setContextClassLoader(cl); cl.run(main.getCanonicalName(), null); } catch (Throwable e) { e.printStackTrace(); } } /** * Generate event list. * * @return the linked list< simulator event> */ public final LinkedList<SimulatorEvent> generateEventList() { LinkedList<SimulatorEvent> eventList = new LinkedList<SimulatorEvent>(); int started = 0; for (StochasticProcess process : processes) { if (!process.relativeStartTime) { eventList.add(process.startEvent); started++; } } if (started == 0) { System.err.println("ERROR: Processes have circular relative start times"); } if (terminatedEvent != null && !terminatedEvent.isRelativeTime()) { eventList.add(terminatedEvent); } return eventList; } public void store() { File file = null; try { file = File.createTempFile("scenario", ".bin"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file)); oos.writeObject(this); oos.flush(); oos.close(); System.setProperty("scenario", file.getAbsolutePath()); } catch (IOException e) { e.printStackTrace(); } } /** * Load. * * @param scenarioFile * the scenario file * * @return the simulation scenario */ public static SimulationScenario load(String scenarioFile) { SimulationScenario scenario = null; try { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(scenarioFile)); scenario = (SimulationScenario) ois.readObject(); ois.close(); } catch (FileNotFoundException e) { e.printStackTrace(); System.exit(0); } catch (IOException e) { e.printStackTrace(); System.exit(0); } catch (ClassNotFoundException e) { e.printStackTrace(); System.exit(0); } return scenario; } /** * Sim. * * @param main * the main * @param args * the args */ public final void sim(Class<? extends ComponentDefinition> main, String... args) { store(); // 1. validate environment: quit if not Sun if (!goodEnv()) { throw new RuntimeException("Only Sun JRE usable for simulation"); } // 2. compute boot-string String bootString = bootString(); // 3. check if it already exists; goto 5 if it does if (!alreadyInstrumentedBoot(bootString)) { // 4. transform and generate boot classes in boot-string directory prepareInstrumentationExceptions(); instrumentBoot(bootString); } else { prepareInstrumentationExceptions(); } // 5. transform and generate application classes instrumentApplication(); // 6. launch simulation process launchSimulation(main, args); } public static void instrument() { // 1. validate environment: quit if not Sun if (!goodEnv()) { throw new RuntimeException("Only Sun JRE usable for simulation"); } // 2. compute boot-string String bootString = bootString(); // 3. check if it already exists; goto 5 if it does if (!alreadyInstrumentedBoot(bootString)) { // 4. transform and generate boot classes in boot-string directory prepareInstrumentationExceptions(); instrumentBoot(bootString); } else { prepareInstrumentationExceptions(); } // 5. transform and generate application classes instrumentApplication(); } /** * Launch simulation. * * @param main * the main * @param args * the args */ private void launchSimulation(Class<? extends ComponentDefinition> main, String... args) { LinkedList<String> arguments = new LinkedList<String>(); String java = System.getProperty("java.home"); String sep = System.getProperty("file.separator"); String pathSep = System.getProperty("path.separator"); java += sep + "bin" + sep + "java"; if (System.getProperty("os.name").startsWith("Windows")) { arguments.add("\"" + java + "\""); } else { arguments.add(java); } arguments.add("-Xbootclasspath:" + directory + bootString() + pathSep + directory + "application"); arguments.add("-classpath"); arguments.add(directory + "application"); arguments.addAll(getJvmArgs(args)); arguments.add("-Dscenario=" + System.getProperty("scenario")); // add configuration properties for (Object key : System.getProperties().keySet()) { if (((String) key).contains("configuration")) arguments.add("-D" + key + "=" + System.getProperty((String) key)); } arguments.add(main.getName()); arguments.addAll(getApplicationArgs(args)); ProcessBuilder pb = new ProcessBuilder(arguments); pb.redirectErrorStream(true); saveSimulationCommandLine(arguments); try { Process process = pb.start(); BufferedReader out = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; do { line = out.readLine(); if (line != null) { System.out.println(line); } } while (line != null); } catch (IOException e) { throw new RuntimeException("Cannot start simulation process", e); } } /** * Save simulation command line. * * @param args * the args */ private void saveSimulationCommandLine(final LinkedList<String> args) { File file = null; try { // Windows batch file file = new File(directory + "run-simulation.bat"); PrintStream ps = new PrintStream(file); for (String arg : args) { ps.println(arg.replaceAll(directory, "") + "\t^"); // ps.println(arg + "\t^"); } ps.println(";"); ps.flush(); ps.close(); // Linux/Unix Bash script file = new File(directory + "run-simulation.sh"); ps = new PrintStream(file); ps.println("#!/bin/bash"); ps.println(); for (String arg : args) { ps.println(arg.replaceAll(directory, "") + "\t\\"); // ps.println(arg + "\t\\"); } ps.println(";"); ps.flush(); ps.close(); } catch (IOException e) { e.printStackTrace(); } } /** * Gets the jvm args. * * @param args * the args * * @return the jvm args */ private LinkedList<String> getJvmArgs(String[] args) { LinkedList<String> list = new LinkedList<String>(); boolean maxHeap = false; for (int i = 0; i < args.length; i++) { if (args[i].startsWith("-JVM:")) { String a = args[i].substring(5); if (a.startsWith("-Xmx")) { maxHeap = true; } if (a.startsWith("-Xbootclasspath") || a.startsWith("-cp") || a.startsWith("-classpath")) { continue; // ignore class-path settings } list.add(a); } } if (!maxHeap) { list.add("-Xmx1g"); } return list; } /** * Gets the application args. * * @param args * the args * * @return the application args */ private LinkedList<String> getApplicationArgs(String[] args) { LinkedList<String> list = new LinkedList<String>(); for (int i = 0; i < args.length; i++) { if (!args[i].startsWith("-JVM:")) { list.add(args[i]); } } return list; } /** The Constant directory. */ private static final String directory = "./target/kompics-simulation/"; /** The exceptions. */ private static HashSet<String> exceptions = new HashSet<String>(); /** * Prepare instrumentation exceptions. */ private static void prepareInstrumentationExceptions() { // well known exceptions exceptions.add("java.lang.ref.Reference"); exceptions.add("java.lang.ref.Finalizer"); exceptions.add("se.sics.kompics.p2p.simulator.P2pSimulator"); exceptions.add("org.apache.log4j.PropertyConfigurator"); exceptions.add("org.apache.log4j.helpers.FileWatchdog"); exceptions.add("org.mortbay.thread.QueuedThreadPool"); exceptions.add("org.mortbay.io.nio.SelectorManager"); exceptions.add("org.mortbay.io.nio.SelectorManager$SelectSet"); exceptions.add("org.apache.commons.math.stat.descriptive.SummaryStatistics"); exceptions.add("org.apache.commons.math.stat.descriptive.DescriptiveStatistics"); // try to add user-defined exceptions from properties file InputStream in = ClassLoader.getSystemResourceAsStream("timer.interceptor.properties"); Properties p = new Properties(); if (in != null) { try { p.load(in); for (String classname : p.stringPropertyNames()) { String value = p.getProperty(classname); if (value != null && value.equals("IGNORE")) { exceptions.add(classname); logger.debug("Adding instrumentation exception {}", classname); } } } catch (IOException e) { e.printStackTrace(); } } else { logger.debug("Could not find timer.interceptor.properties"); } } /** * Instrument boot. * * @param bootString * the boot string */ private static void instrumentBoot(String bootString) { String bootCp = System.getProperty("sun.boot.class.path"); try { transformClasses(bootCp, bootString); copyResources(bootCp, bootString); } catch (Throwable t) { throw new RuntimeException("Exception caught while preparing simulation", t); } } /** * Instrument application. */ private static void instrumentApplication() { String cp = System.getProperty("java.class.path"); try { transformClasses(cp, null); copyResources(cp, null); } catch (Throwable t) { throw new RuntimeException("Exception caught while preparing simulation", t); } } /** * Transform classes. * * @param classPath * the class path * @param boot * the boot * * @throws IOException * Signals that an I/O exception has occurred. * @throws NotFoundException * the not found exception * @throws CannotCompileException * the cannot compile exception */ private static void transformClasses(String classPath, String boot) throws IOException, NotFoundException, CannotCompileException { LinkedList<String> classes = getAllClasses(classPath); ClassPool pool = new ClassPool(); pool.appendSystemPath(); String target = directory; if (boot == null) { pool.appendPathList(classPath); target += "application"; logger.info("Instrumenting application classes to:" + target); } else { target += boot; logger.info("Instrumenting bootstrap classes to:" + target); } CodeInstrumenter ci = new CodeInstrumenter(); int count = classes.size(); long start = System.currentTimeMillis(); for (final String classname : classes) { int d = classname.indexOf("$"); String outerClass = (d == -1 ? classname : classname.substring(0, d)); CtClass ctc = pool.getCtClass(classname); if (!exceptions.contains(outerClass)) { ctc.defrost(); ctc.instrument(ci); } else { logger.trace("Skipping " + classname); } saveClass(ctc, target); } long stop = System.currentTimeMillis(); logger.info("It took " + (stop - start) + "ms to instrument " + count + " classes."); } /** * Already instrumented boot. * * @param bootString * the boot string * * @return true, if successful */ private static boolean alreadyInstrumentedBoot(String bootString) { File f = new File(directory + bootString); return f.exists() && f.isDirectory(); } /** * Boot string. * * @return the string */ private static String bootString() { String os = System.getProperty("os.name"); int sp = os.indexOf(' '); if (sp != -1) { os = os.substring(0, sp); } String vendor = System.getProperty("java.vendor"); sp = vendor.indexOf(' '); if (sp != -1) { vendor = vendor.substring(0, sp); } return "boot-" + vendor + "-" + System.getProperty("java.version") + "-" + os + "-" + System.getProperty("os.arch"); } /** * Good env. * * @return true, if successful */ private static boolean goodEnv() { if (System.getProperty("java.vendor").startsWith("Sun")) return true; if (System.getProperty("java.vendor").startsWith("Oracle")) return true; // we should change this method to accept more (or less) Java // environments known to be (un)acceptable for our instrumentation return false; } /** * Save class. * * @param cc * the cc * @param dir * the dir */ private static void saveClass(CtClass cc, String dir) { File directory = new File(dir); if (directory != null) { try { cc.writeFile(directory.getAbsolutePath()); } catch (CannotCompileException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } /** * Copy resources. * * @param classPath * the class path * @param boot * the boot * * @throws IOException * Signals that an I/O exception has occurred. */ private static void copyResources(String classPath, String boot) throws IOException { LinkedList<String> resources = getAllResources(classPath); String target = directory; if (boot == null) { target += "application"; logger.info("Copying application resources to:" + target); } else { target += boot; logger.info("Copying bootstrap resources to:" + target); } int count = resources.size(); long start = System.currentTimeMillis(); for (final String resourceName : resources) { InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName); String targetFile = target + "/" + resourceName; File dir = new File(new File(targetFile).getParent()); if (!dir.exists()) { dir.mkdirs(); dir.setWritable(true); } OutputStream os = new FileOutputStream(targetFile); byte buffer[] = new byte[65536]; int len; long ms = System.currentTimeMillis(); // copy the resource while ((len = is.read(buffer)) > 0) { os.write(buffer, 0, len); } is.close(); os.close(); ms = System.currentTimeMillis() - ms; logger.trace( "Copying " + resourceName + " to " + (target + "/" + resourceName) + " - took " + ms + "ms."); } long stop = System.currentTimeMillis(); logger.info("It took " + (stop - start) + "ms to copy " + count + " resources."); } /** * Gets the all classes. * * @param cp * the cp * * @return the all classes * * @throws IOException * Signals that an I/O exception has occurred. */ private static LinkedList<String> getAllClasses(String cp) throws IOException { LinkedList<String> list = new LinkedList<String>(); for (String location : getAllLocations(cp)) { list.addAll(getClassesFromLocation(location)); } return list; } /** * Gets the all resources. * * @param cp * the cp * * @return the all resources * * @throws IOException * Signals that an I/O exception has occurred. */ private static LinkedList<String> getAllResources(String cp) throws IOException { LinkedList<String> list = new LinkedList<String>(); for (String location : getAllLocations(cp)) { list.addAll(getResourcesFromLocation(location)); } return list; } /** * Gets the all locations. * * @param cp * the cp * * @return the all locations */ private static LinkedList<String> getAllLocations(String cp) { LinkedList<String> list = new LinkedList<String>(); for (String string : cp.split(System.getProperty("path.separator"))) { list.add(string); } return list; } /** * Gets the classes from location. * * @param location * the location * * @return the classes from location * * @throws IOException * Signals that an I/O exception has occurred. */ private static LinkedList<String> getClassesFromLocation(String location) throws IOException { File f = new File(location); if (f.exists() && f.isDirectory()) { return getClassesFromDirectory(f, ""); } if (f.exists() && f.isFile() && f.getName().endsWith(".jar")) { return getClassesFromJar(f); } LinkedList<String> list = new LinkedList<String>(); return list; } /** * Gets the classes from jar. * * @param jar * the jar * * @return the classes from jar * * @throws IOException * Signals that an I/O exception has occurred. */ private static LinkedList<String> getClassesFromJar(File jar) throws IOException { JarFile j = new JarFile(jar); LinkedList<String> list = new LinkedList<String>(); // System.err.println("Jar entries: " + j.size()); Enumeration<JarEntry> entries = j.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); if (entry.getName().endsWith(".class")) { String className = entry.getName().substring(0, entry.getName().lastIndexOf('.')); list.add(className.replace('/', '.')); } // System.err.println(entry); } return list; } /** * Gets the classes from directory. * * @param directory * the directory * @param pack * the pack * * @return the classes from directory */ private static LinkedList<String> getClassesFromDirectory(File directory, String pack) { String[] files = directory.list(); LinkedList<String> list = new LinkedList<String>(); for (String string : files) { File f = new File(directory + System.getProperty("file.separator") + string); if (f.isFile() && f.getName().endsWith(".class")) { String className = f.getName().substring(0, f.getName().lastIndexOf('.')); list.add(pack + className); } if (f.isDirectory()) { LinkedList<String> classes = getClassesFromDirectory(f, pack + f.getName() + "."); list.addAll(classes); } } return list; } /** * Gets the resources from location. * * @param location * the location * * @return the resources from location * * @throws IOException * Signals that an I/O exception has occurred. */ private static LinkedList<String> getResourcesFromLocation(String location) throws IOException { File f = new File(location); if (f.exists() && f.isDirectory()) { return getResourcesFromDirectory(f, ""); } if (f.exists() && f.isFile() && f.getName().endsWith(".jar")) { return getResourcesFromJar(f); } LinkedList<String> list = new LinkedList<String>(); return list; } /** * Gets the resources from jar. * * @param jar * the jar * * @return the resources from jar * * @throws IOException * Signals that an I/O exception has occurred. */ private static LinkedList<String> getResourcesFromJar(File jar) throws IOException { JarFile j = new JarFile(jar); LinkedList<String> list = new LinkedList<String>(); Enumeration<JarEntry> entries = j.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); if (!entry.getName().endsWith(".class") && !entry.isDirectory() && !entry.getName().startsWith("META-INF")) { String resourceName = entry.getName(); list.add(resourceName); } } return list; } /** * Gets the resources from directory. * * @param directory * the directory * @param pack * the pack * * @return the resources from directory */ private static LinkedList<String> getResourcesFromDirectory(File directory, String pack) { String[] files = directory.list(); LinkedList<String> list = new LinkedList<String>(); for (String string : files) { File f = new File(directory + System.getProperty("file.separator") + string); if (f.isFile() && !f.getName().endsWith(".class")) { String resourceName = f.getName(); list.add(pack + resourceName); } if (f.isDirectory()) { LinkedList<String> resources = getResourcesFromDirectory(f, pack + f.getName() + "/"); list.addAll(resources); } } return list; } }