*** empty log message ***
[IRC.git] / Robust / Transactions / jcarderdstm2version / src / com / enea / jcarder / agent / JavaAgent.java
diff --git a/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/JavaAgent.java b/Robust/Transactions/jcarderdstm2version/src/com/enea/jcarder/agent/JavaAgent.java
new file mode 100644 (file)
index 0000000..a37c652
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * JCarder -- cards Java programs to keep threads disentangled
+ *
+ * Copyright (C) 2006-2007 Enea AB
+ * Copyright (C) 2007 Ulrik Svensson
+ * Copyright (C) 2007 Joel Rosdahl
+ *
+ * This program is made available under the GNU GPL version 2, with a special
+ * exception for linking with JUnit. See the accompanying file LICENSE.txt for
+ * details.
+ *
+ * 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.
+ */
+
+package com.enea.jcarder.agent;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.instrument.Instrumentation;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+
+import com.enea.jcarder.agent.instrument.ClassTransformer;
+import com.enea.jcarder.agent.instrument.InstrumentConfig;
+import com.enea.jcarder.util.BuildInformation;
+import com.enea.jcarder.util.logging.AppendableHandler;
+import com.enea.jcarder.util.logging.Handler;
+import com.enea.jcarder.util.logging.Logger;
+import dstm2.Init;
+
+/**
+ * This is the main class of the JCarder Java agent. It will initialize JCarder
+ * and register a ClassTransformer that is called by the JVM each time a class
+ * is loaded.
+ */
+public final class JavaAgent {
+
+    private static final String DUMP_PROPERTY = "jcarder.dump";
+    private static final String LOGLEVEL_PROPERTY = "jcarder.loglevel";
+    private static final String LOG_FILENAME = "jcarder.log";
+
+    private final InstrumentConfig mConfig = new InstrumentConfig();
+    private Logger mLogger;
+    PrintWriter mLogWriter;
+    private File mOutputDir;
+    private Logger.Level mLogLevel;
+    private static final String OUTPUTDIR_PROPERTY = "jcarder.outputdir";
+
+    private JavaAgent() { }
+
+    /**
+     * This method is called by the JVM when the JVM is started with the
+     * -javaagent command line parameter.
+     */
+    public static void premain(final String args,
+                               final Instrumentation instrumentation)
+    throws Exception {
+         Init.init();
+        JavaAgent javaAgent = new JavaAgent();
+        javaAgent.init(instrumentation);
+    }
+
+    private void init(Instrumentation instrumentation)
+    throws Exception {
+        handleProperties();
+        initLogger();
+        mLogger.info("Starting " + BuildInformation.getShortInfo() + " agent");
+        logJvmInfo();
+        EventListener listener = EventListener.create(mLogger, mOutputDir);
+        ClassTransformer classTransformer =
+            new ClassTransformer(mLogger, mOutputDir, mConfig);
+        instrumentation.addTransformer(classTransformer);
+        StaticEventListener.setListener(listener);
+        mLogger.info("JCarder agent initialized\n");
+    }
+
+    private void initLogger() {
+        File logFile = new File(mOutputDir, LOG_FILENAME);
+        if (logFile.exists()) {
+            logFile.delete();
+        }
+        FileWriter fileWriter;
+        try {
+            fileWriter = new FileWriter(logFile);
+        } catch (IOException e) {
+            System.err.println("Failed to open log file \""
+                               + logFile + "\": " + e.getMessage());
+            return;
+        }
+        mLogWriter = new PrintWriter(new BufferedWriter(fileWriter));
+        AppendableHandler fileHandler = new AppendableHandler(mLogWriter);
+        AppendableHandler consoleHandler =
+            new AppendableHandler(System.err, Logger.Level.INFO, "{message}\n");
+
+        Thread hook = new Thread() {
+            public void run() {
+                mLogWriter.flush();
+            }
+        };
+        Runtime.getRuntime().addShutdownHook(hook);
+
+        Collection<Handler> handlers = new ArrayList<Handler>();
+        handlers.add(fileHandler);
+        handlers.add(consoleHandler);
+        mLogger = new Logger(handlers, mLogLevel);
+    }
+
+    private void logJvmInfo() {
+        Enumeration<?> properties = System.getProperties().propertyNames();
+        while (properties.hasMoreElements()) {
+            String key = (String) properties.nextElement();
+            if (key.startsWith("java.vm.")) {
+                mLogger.config(key + ": " + System.getProperty(key));
+            }
+        }
+    }
+
+    private void handleProperties() throws IOException {
+        handleDumpProperty();
+        handleLogLevelProperty();
+        handleOutputDirProperty();
+    }
+
+    private void handleDumpProperty() {
+        mConfig.setDumpClassFiles(Boolean.getBoolean(DUMP_PROPERTY));
+    }
+
+    private void handleLogLevelProperty() {
+        String logLevelValue = System.getProperty(LOGLEVEL_PROPERTY, "fine");
+        Logger.Level logLevel = Logger.Level.fromString(logLevelValue);
+        if (logLevel != null) {
+            mLogLevel = logLevel;
+        } else {
+            System.err.print("Bad loglevel; should be one of ");
+            System.err.println(Logger.Level.getEnumeration());
+            System.err.println();
+            System.exit(1);
+        }
+    }
+
+    private void handleOutputDirProperty() throws IOException {
+        final String property = System.getProperty(OUTPUTDIR_PROPERTY, ".");
+        mOutputDir = new File(property).getCanonicalFile();
+        if (!mOutputDir.isDirectory()) {
+            mOutputDir.mkdirs();
+        }
+    }
+}