[jboss-cvs] JBoss Profiler SVN: r549 - in branches/JBossProfiler2: doc/userguide/en/modules and 5 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Sun Jun 21 13:24:31 EDT 2009


Author: jesper.pedersen
Date: 2009-06-21 13:24:30 -0400 (Sun, 21 Jun 2009)
New Revision: 549

Added:
   branches/JBossProfiler2/src/etc/precompiler-manifest.mf
   branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/
   branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/ArchiveUtil.java
   branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/ClassInstrumenter.java
   branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/ClassScanner.java
   branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/ExtensionScanner.java
   branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/FileUtil.java
   branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/JarScanner.java
   branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/Precompiler.java
   branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/SizeComparator.java
   branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/package.html
Modified:
   branches/JBossProfiler2/build.xml
   branches/JBossProfiler2/doc/userguide/en/modules/client.xml
   branches/JBossProfiler2/doc/userguide/en/modules/configuration.xml
   branches/JBossProfiler2/src/etc/jboss-profiler.properties
   branches/JBossProfiler2/src/main/org/jboss/profiler/agent/Agent.java
   branches/JBossProfiler2/src/main/org/jboss/profiler/agent/ClassUtil.java
   branches/JBossProfiler2/src/main/org/jboss/profiler/client/CombinedFrameInfo.java
   branches/JBossProfiler2/src/main/org/jboss/profiler/client/SnapshotUtil.java
   branches/JBossProfiler2/src/main/org/jboss/profiler/client/TimedClassInfo.java
   branches/JBossProfiler2/src/main/org/jboss/profiler/shared/ClassInfo.java
   branches/JBossProfiler2/src/main/org/jboss/profiler/shared/MethodInfo.java
Log:
[JBPROFILER-82] Precompiler

Modified: branches/JBossProfiler2/build.xml
===================================================================
--- branches/JBossProfiler2/build.xml	2009-06-16 01:51:25 UTC (rev 548)
+++ branches/JBossProfiler2/build.xml	2009-06-21 17:24:30 UTC (rev 549)
@@ -25,6 +25,7 @@
     <property name="jboss-profiler-client.jar" value="jboss-profiler-client.jar"/>
     <property name="jboss-profiler-embedded.jar" value="jboss-profiler-embedded.jar"/>
     <property name="jboss-profiler-plugins.jar" value="jboss-profiler-plugins.jar"/>
+    <property name="jboss-profiler-precompiler.jar" value="jboss-profiler-precompiler.jar"/>
     <property name="jboss-profiler-test.jar" value="jboss-profiler-test.jar"/>
     <property name="jboss-profiler.war" value="jboss-profiler.war"/>
 
@@ -243,6 +244,36 @@
     </target>
 
     <!-- =================================================================== -->
+    <!-- Precompiler                                                         -->
+    <!-- =================================================================== -->
+    <target name="precompiler" depends="prepare">
+        <delete dir="${build.dir}"/>
+        <mkdir dir="${build.dir}"/>
+        <javac
+            destdir="${build.dir}"
+            classpathref="class.path"
+            debug="on"
+            deprecation="on"
+            optimize="off"
+            source="1.5"
+            target="1.5"
+            >
+            <src path="${src.main.dir}"/>
+        </javac>
+        <copy todir="${build.dir}">
+            <fileset dir="${etc.dir}">
+               <include name="**/log4j.xml"/>
+            </fileset>
+        </copy>
+
+        <jar destfile="${dist.dir}/${jboss-profiler-precompiler.jar}"
+             basedir="${build.dir}"
+             manifest="${etc.dir}/precompiler-manifest.mf"
+             includes="org/jboss/profiler/agent/**,org/jboss/profiler/client/precompiler/**,org/jboss/profiler/shared/**,**/*.xml"
+             excludes="**/*.java"/>
+    </target>
+
+    <!-- =================================================================== -->
     <!-- Web                                                                 -->
     <!-- =================================================================== -->
     <target name="web" depends="prepare">
@@ -406,7 +437,7 @@
     <!-- =================================================================== -->
     <!-- Dist                                                                -->
     <!-- =================================================================== -->
-    <target name="dist" depends="agent,connectors,ant,client,embedded,plugins,test,sar">
+    <target name="dist" depends="agent,connectors,ant,client,embedded,plugins,precompiler,test,sar">
         <copy todir="${dist.dir}">
             <fileset dir="${lib.dir}">
                <include name="**/*.jar"/>

Modified: branches/JBossProfiler2/doc/userguide/en/modules/client.xml
===================================================================
--- branches/JBossProfiler2/doc/userguide/en/modules/client.xml	2009-06-16 01:51:25 UTC (rev 548)
+++ branches/JBossProfiler2/doc/userguide/en/modules/client.xml	2009-06-21 17:24:30 UTC (rev 549)
@@ -278,4 +278,27 @@
        </programlisting>
      </section>
 
+     <section id="precompiler">
+       <title>Using the precompiler</title>
+       <warning>The JBoss Profiler precompiler will overwrite the JAR files in your application, so
+         make sure that you keep a copy of the original files.</warning>
+
+       <para>The JBoss Profiler precompiler will precompile the JAR archives in the specifed directory
+         with instrumentation information used by the agent. This allows you to start up your 
+         application quicker.</para>
+       <para>The precompiler is run using the following command:</para>
+       <programlisting>
+java -Xmx1024m -jar jboss-profiler-precompiler.jar \
+  &lt;includes&gt; &lt;excludes&gt; &lt;visibility&gt; &lt;file|directory&gt;
+       </programlisting>
+       <para>The includes, excludes and visibility flags are in the same format as the flags for the agent. 
+         An example:</para>
+       <programlisting>
+java -Xmx1024m -jar jboss-profiler-precompiler.jar \
+  com.mycompany.* com.mycompany.highperformance.*,* private ~/myapplication
+       </programlisting>
+       <para>The precompiler will output any classes it can't precompile due to missing dependencies and the
+         statistics for the run.</para>
+     </section>
+
 </chapter>

Modified: branches/JBossProfiler2/doc/userguide/en/modules/configuration.xml
===================================================================
--- branches/JBossProfiler2/doc/userguide/en/modules/configuration.xml	2009-06-16 01:51:25 UTC (rev 548)
+++ branches/JBossProfiler2/doc/userguide/en/modules/configuration.xml	2009-06-21 17:24:30 UTC (rev 549)
@@ -30,6 +30,13 @@
              </entry>
            </row>
            <row>
+             <entry>precompiled</entry>
+             <entry>
+               <para>Use precompiled archives.</para>
+               <para>[yes|no] default: no.</para>
+             </entry>
+           </row>
+           <row>
              <entry>cpu</entry>
              <entry>
                <para>Enable / disable CPU profiling.</para>

Modified: branches/JBossProfiler2/src/etc/jboss-profiler.properties
===================================================================
--- branches/JBossProfiler2/src/etc/jboss-profiler.properties	2009-06-16 01:51:25 UTC (rev 548)
+++ branches/JBossProfiler2/src/etc/jboss-profiler.properties	2009-06-21 17:24:30 UTC (rev 549)
@@ -1,4 +1,5 @@
 enable=yes
+precompiled=no
 cpu=yes
 memory=yes
 includes=org.jboss.profiler.*

Added: branches/JBossProfiler2/src/etc/precompiler-manifest.mf
===================================================================
--- branches/JBossProfiler2/src/etc/precompiler-manifest.mf	                        (rev 0)
+++ branches/JBossProfiler2/src/etc/precompiler-manifest.mf	2009-06-21 17:24:30 UTC (rev 549)
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: org.jboss.profiler.client.precompiler.Precompiler
+Class-Path: jboss-profiler-precompiler.jar javassist.jar jboss-common.jar log4j.jar

Modified: branches/JBossProfiler2/src/main/org/jboss/profiler/agent/Agent.java
===================================================================
--- branches/JBossProfiler2/src/main/org/jboss/profiler/agent/Agent.java	2009-06-16 01:51:25 UTC (rev 548)
+++ branches/JBossProfiler2/src/main/org/jboss/profiler/agent/Agent.java	2009-06-21 17:24:30 UTC (rev 549)
@@ -63,6 +63,9 @@
   /** Enabled */
   private static boolean enabled = true;
 
+  /** Precompiled */
+  private static boolean precompiled = false;
+
   /** CPU */
   private static boolean cpu = true;
 
@@ -203,6 +206,7 @@
     parse(properties.getProperty("includes"), properties.getProperty("excludes"));
 
     enabled = parseBoolean(properties.getProperty("enable"), true);
+    precompiled = parseBoolean(properties.getProperty("precompiled"), false);
     cpu = parseBoolean(properties.getProperty("cpu"), true);
     memory = parseBoolean(properties.getProperty("memory"), true);
     remote = parseBoolean(properties.getProperty("remote"), true);
@@ -454,6 +458,14 @@
   }
 
   /**
+   * Is the profiler in precompiled mode ?
+   * @return True if the profiler is in precompiled mode; otherwise false
+   */
+  public static boolean isPrecompiled() {
+    return precompiled;
+  }
+
+  /**
    * Is the CPU profiling enabled ?
    * @return True if enabled; otherwise false
    */
@@ -513,7 +525,7 @@
    * @param className The class name
    * @return True if the class is approved; otherwise false
    */
-  private static boolean approve(String className) {
+  static boolean approve(String className) {
     // We can't profile the profiler, Java / Sun classes 
     // nor Javassist
     if (className.startsWith("org/jboss/profiler/agent/") ||
@@ -634,7 +646,7 @@
    * @param v The visibility
    */
   public static void addClasses(String classes, Visibility v) {
-    if (isRepository()) {
+    if (isRepository() && !precompiled) {
 
       if (classes.endsWith(".*")) {
         classes = classes.substring(0, classes.indexOf(".*")) + "/";
@@ -702,7 +714,7 @@
    * @param classes The classes
    */
   public static void removeClasses(String classes) {
-    if (isRepository()) {
+    if (isRepository() && !precompiled) {
       boolean all = false;
 
       if (classes.endsWith(".*")) {
@@ -756,19 +768,22 @@
    * @return The classes
    */
   public static String[] listClasses() {
-    String[] result = new String[includeList.size()];
-    for (int i = 0; i < includeList.size(); i++) {
-      String s = includeList.get(i);
-
-      if (s.endsWith("/")) {
-        s = s.substring(0, s.length() - 1) + ".*";
+    if (!precompiled) {
+      String[] result = new String[includeList.size()];
+      for (int i = 0; i < includeList.size(); i++) {
+        String s = includeList.get(i);
+        
+        if (s.endsWith("/")) {
+          s = s.substring(0, s.length() - 1) + ".*";
+        }
+        
+        s = s.replace('/', '.');
+        
+        result[i] = s;
       }
-
-      s = s.replace('/', '.');
-
-      result[i] = s;
+      return result;
     }
-    return result;
+    return null;
   }
 
   /**
@@ -882,11 +897,13 @@
       System.out.println("JBoss Profiler not enabled");
     }
 
-    checkInstrumentation();
-    transformer = new JavassistTransformer();
     instrumentation = inst;
-    instrumentation.addTransformer(transformer);
 
+    if (!precompiled && checkInstrumentation()) {
+      transformer = new JavassistTransformer();
+      instrumentation.addTransformer(transformer);
+    }
+
     if (save || remote) {
       Runtime.getRuntime().addShutdownHook(new Thread() {
         @Override

Modified: branches/JBossProfiler2/src/main/org/jboss/profiler/agent/ClassUtil.java
===================================================================
--- branches/JBossProfiler2/src/main/org/jboss/profiler/agent/ClassUtil.java	2009-06-16 01:51:25 UTC (rev 548)
+++ branches/JBossProfiler2/src/main/org/jboss/profiler/agent/ClassUtil.java	2009-06-21 17:24:30 UTC (rev 549)
@@ -88,7 +88,9 @@
             !c.isAnnotation() && 
             !c.isSynthetic()) {
           String className = c.getName().replace(".", "/");
-          if (Agent.accept(className) && !processed.contains(className)) {
+          if (((Agent.isPrecompiled() && Agent.approve(className)) || Agent.accept(className)) && 
+              !processed.contains(className)) {
+
             int ct = ClassType.POJO;
             
             if (Agent.isEJB() && isSession(c)) {

Modified: branches/JBossProfiler2/src/main/org/jboss/profiler/client/CombinedFrameInfo.java
===================================================================
--- branches/JBossProfiler2/src/main/org/jboss/profiler/client/CombinedFrameInfo.java	2009-06-16 01:51:25 UTC (rev 548)
+++ branches/JBossProfiler2/src/main/org/jboss/profiler/client/CombinedFrameInfo.java	2009-06-21 17:24:30 UTC (rev 549)
@@ -139,4 +139,13 @@
   public void increaseWaitTime(double t) {
     wait += t;
   }
+
+  /**
+   * Get the string representation
+   * @return The string
+   */
+  @Override
+  public String toString() {
+    return className + "," + prettyName + "," + count + "," + time  + "," + percent  + "," + wait;  
+  }
 }

Modified: branches/JBossProfiler2/src/main/org/jboss/profiler/client/SnapshotUtil.java
===================================================================
--- branches/JBossProfiler2/src/main/org/jboss/profiler/client/SnapshotUtil.java	2009-06-16 01:51:25 UTC (rev 548)
+++ branches/JBossProfiler2/src/main/org/jboss/profiler/client/SnapshotUtil.java	2009-06-21 17:24:30 UTC (rev 549)
@@ -881,7 +881,7 @@
     bw.write("<h1>" + Util.getPrettyName(tci) + " (" + Util.getDescription(tci) + ")</h1>" + NEW_LINE);
     
     DecimalFormat df = new DecimalFormat("#0.00");
-    
+
     bw.write("<table>" + NEW_LINE);
     bw.write("  <tr class=\"rowodd\">" + NEW_LINE);
     bw.write("    <td>Total time</td><td>" + df.format(tci.getTotalTime()) + " ms</td>" + NEW_LINE);

Modified: branches/JBossProfiler2/src/main/org/jboss/profiler/client/TimedClassInfo.java
===================================================================
--- branches/JBossProfiler2/src/main/org/jboss/profiler/client/TimedClassInfo.java	2009-06-16 01:51:25 UTC (rev 548)
+++ branches/JBossProfiler2/src/main/org/jboss/profiler/client/TimedClassInfo.java	2009-06-21 17:24:30 UTC (rev 549)
@@ -64,4 +64,13 @@
   public double getWaitTime() {
     return wait;
   }
+
+  /**
+   * Get the string representation
+   * @return The string
+   */
+  @Override
+  public String toString() {
+    return super.toString() + "," + time + "," + wait; 
+  }
 }

Added: branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/ArchiveUtil.java
===================================================================
--- branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/ArchiveUtil.java	                        (rev 0)
+++ branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/ArchiveUtil.java	2009-06-21 17:24:30 UTC (rev 549)
@@ -0,0 +1,161 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2007-2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.profiler.client.precompiler;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+
+import org.jboss.logging.Logger;
+
+/**
+ * An archive utility for JAR type files
+ * @author <a href="mailto:jesper.pedersen at jboss.org">Jesper Pedersen</a>
+ */
+public class ArchiveUtil {
+
+  /**
+   * Constructor
+   */
+  private ArchiveUtil() {
+  }
+
+  /**
+   * Compress a directory to a file
+   * @param directory The directory
+   * @param file The file
+   * @exception IOException Thrown if an error occurs
+   */
+  public static void compress(File directory, File file) throws IOException {
+    FileOutputStream fos = new FileOutputStream(file);
+    BufferedOutputStream bos = new BufferedOutputStream(fos);
+    JarOutputStream jos = new JarOutputStream(bos);
+    jos.setLevel(9);
+
+    jarDirectory(directory.getPath(), directory.getPath(), jos);
+
+    jos.flush();
+    jos.close();
+  }
+
+  private static void jarDirectory(String root, String directory, JarOutputStream jos) throws IOException { 
+    File jarDirectory = new File(directory);
+    String[] dirList = jarDirectory.list(); 
+    byte[] readBuffer = new byte[2156]; 
+    int bytesIn = 0; 
+    
+    for (int i = 0; i < dirList.length; i++) { 
+      File f = new File(jarDirectory, dirList[i]); 
+      if (f.isDirectory()) { 
+        String filePath = f.getPath(); 
+        jarDirectory(root, filePath, jos); 
+        continue; 
+      } 
+      
+      FileInputStream fis = new FileInputStream(f); 
+
+      String name = f.getPath();
+      if (name.startsWith(root)) {
+        int offset = root.length() + File.separator.length(); 
+        name = name.substring(offset);
+      }
+
+      JarEntry anEntry = new JarEntry(name); 
+      jos.putNextEntry(anEntry); 
+      
+      while ((bytesIn = fis.read(readBuffer)) != -1) { 
+        jos.write(readBuffer, 0, bytesIn); 
+      } 
+      fis.close(); 
+    } 
+  } 
+
+  /**
+   * Extract a JAR type file
+   * @param file The file
+   * @param directory The directory where the file should be extracted
+   * @return The root of the extracted JAR file
+   * @exception IOException Thrown if an error occurs
+   */
+  public static File extract(File file, File directory) throws IOException {
+    if (file == null) {
+      throw new IllegalArgumentException("File is null");
+    }
+
+    if (directory == null) {
+      throw new IllegalArgumentException("Directory is null");
+    }
+
+    File target = new File(directory, file.getName());
+
+    if (target.exists()) {
+      FileUtil.recursiveDelete(target);
+    }
+
+    target.mkdirs();
+
+    JarFile jar = new JarFile(file);
+    Enumeration<JarEntry> entries = jar.entries();
+
+    while (entries.hasMoreElements()) {
+      JarEntry je = entries.nextElement();
+      File copy = new File(target, je.getName());
+
+      int idx = copy.getAbsolutePath().lastIndexOf("/");
+      if (idx != -1) {
+        File f = new File(copy.getAbsolutePath().substring(0, idx));
+        f.mkdirs();
+      }
+
+      if (!je.isDirectory()) {
+        InputStream in = new BufferedInputStream(jar.getInputStream(je));
+        OutputStream out = new BufferedOutputStream(new FileOutputStream(copy));
+
+        byte[] buffer = new byte[4096];
+        for (;;) {
+          int nBytes = in.read(buffer);
+          if (nBytes <= 0) {
+            break;
+          }
+
+          out.write(buffer, 0, nBytes);
+        }
+        out.flush();
+        out.close();
+        in.close();
+      } else {
+        copy.mkdirs();
+      }
+    }
+
+    return target;
+  }
+}

Added: branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/ClassInstrumenter.java
===================================================================
--- branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/ClassInstrumenter.java	                        (rev 0)
+++ branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/ClassInstrumenter.java	2009-06-21 17:24:30 UTC (rev 549)
@@ -0,0 +1,212 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2007-2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.profiler.client.precompiler;
+
+import org.jboss.profiler.shared.Visibility;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtBehavior;
+import javassist.CtClass;
+import javassist.CtConstructor;
+import javassist.CtMethod;
+import javassist.Modifier;
+import javassist.expr.ExprEditor;
+import javassist.expr.MethodCall;
+
+/**
+ * Instrument a class with profiler instructions
+ * @author Jesper Pedersen <jesper.pedersen at jboss.org>
+ */
+public class ClassInstrumenter {
+
+  /** Prefix */
+  private static final String PREFIX = "org.jboss.profiler.agent.Profiler.getProfilerThread(Thread.currentThread())";
+
+  /** */
+  private static final String CODE = "{" + PREFIX + ".beginWait(); $_ = $proceed($$); " + PREFIX + ".endWait();}";
+
+  /**
+   * Constructor
+   */
+  private ClassInstrumenter() {
+  }
+
+  /**
+   * Get the bytecode for the instrumented class
+   * @param cc The CtClass that is being instrumented
+   * @param v The visibility for the class
+   * @return The instrumented bytes
+   * @exception IOException If an error occurs
+   */
+  public static byte[] instrument(CtClass cc, Visibility v) throws IOException {
+    try {
+      String className = cc.getName().replace('.', '/');
+
+      if (Modifier.isInterface(cc.getModifiers())) {
+        return cc.toBytecode();
+      }
+
+      CtConstructor[] constructors =  cc.getDeclaredConstructors();
+      for (int i = 0; i < constructors.length; i++) {
+        CtConstructor constructor = constructors[i];
+        if (!Modifier.isAbstract(constructor.getModifiers())) {
+          instrumentConstructor(constructor, className, v);
+        }
+      }
+
+      CtMethod[] methods =  cc.getDeclaredMethods();
+      for (int i = 0; i < methods.length; i++) {
+        CtMethod method = methods[i];
+        if (!Modifier.isAbstract(method.getModifiers())) {
+          instrumentMethod(method, className, v);
+        }
+      }
+
+      return cc.toBytecode();
+
+    } catch (Exception e) {
+      IOException ioe = new IOException(e.getMessage());
+      ioe.initCause(e);
+      throw ioe;
+    }
+  }
+
+  /**
+   * Instrument constructor
+   * @param constructor The constructor
+   * @param className The class name
+   * @param v The visibility
+   * @exception CannotCompileException If the constructor cant be modified
+   */
+  private static void instrumentConstructor(CtConstructor constructor, 
+                                            String className, 
+                                            Visibility v) 
+    throws CannotCompileException {
+
+    if (!constructor.isClassInitializer()) {
+      boolean include = true;
+      
+      if (Modifier.isPrivate(constructor.getModifiers())) {
+        if (v == Visibility.PROTECTED ||
+            v == Visibility.PACKAGE ||
+            v == Visibility.PUBLIC) {
+          include = false;
+        }
+      } else if (Modifier.isProtected(constructor.getModifiers())) {
+        if (v == Visibility.PACKAGE ||
+            v == Visibility.PUBLIC) {
+          include = false;
+        }
+      } else if (Modifier.isPackage(constructor.getModifiers())) {
+        if (v == Visibility.PUBLIC) {
+          include = false;
+        }
+      }
+      // Modifier.PUBLIC -- no need to check for method visibility
+      
+      if (include) {
+        constructor.insertBeforeBody("{ " +
+                                     PREFIX + ".allocation(\"" + className + "\");" +
+                                     PREFIX + ".start(\"" + className + "\", \"" + constructor.getLongName() + "\");" +
+                                     " }");
+
+        constructor.insertAfter("{ " +
+                                PREFIX + ".end(\"" + className + "\", \"" + constructor.getLongName() + "\");" +
+                                " }", true);
+        
+        setup(constructor);
+      }
+    }
+  }
+
+  /**
+   * Instrument method
+   * @param method The method
+   * @param className The class name
+   * @param v The visibility
+   * @exception CannotCompileException If the constructor cant be modified
+   */
+  private static void instrumentMethod(CtMethod method, String className, Visibility v) throws CannotCompileException {
+    boolean include = true;
+      
+    if (Modifier.isPrivate(method.getModifiers())) {
+      if (v == Visibility.PROTECTED ||
+          v == Visibility.PACKAGE ||
+          v == Visibility.PUBLIC) {
+        include = false;
+      }
+    } else if (Modifier.isProtected(method.getModifiers())) {
+      if (v == Visibility.PACKAGE ||
+          v == Visibility.PUBLIC) {
+        include = false;
+      }
+    } else if (Modifier.isPackage(method.getModifiers())) {
+      if (v == Visibility.PUBLIC) {
+        include = false;
+      }
+    }
+    // Modifier.PUBLIC -- no need to check for method visibility
+    
+    if (include) {
+      method.insertBefore("{ " +
+                          PREFIX + ".start(\"" + className + "\", \"" + method.getLongName() + "\");" +
+                          " }");
+      
+      method.insertAfter("{ " +
+                         PREFIX + ".end(\"" + className + "\", \"" + method.getLongName() + "\");" +
+                         " }", true);
+
+      setup(method);
+    }
+  }
+
+  /**
+   * Setup the beginWait/endWait methods
+   * @param ctb The behavior
+   */
+  private static void setup(CtBehavior ctb) {
+    try {
+      ctb.instrument(new ExprEditor() {
+          public void edit(MethodCall m) throws CannotCompileException {
+            if ("java.lang.Object".equals(m.getClassName())) {
+              if ("wait".equals(m.getMethodName())) {
+                m.replace(CODE);
+              }
+            } else if ("java.lang.Thread".equals(m.getClassName())) {
+              if ("join".equals(m.getMethodName()) ||
+                  "sleep".equals(m.getMethodName()) ||
+                  "yield".equals(m.getMethodName())) {
+                m.replace(CODE);
+              }
+            }
+          }
+        });
+
+    } catch (Exception e) {
+      e.printStackTrace(System.err);
+    }
+  }
+}

Added: branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/ClassScanner.java
===================================================================
--- branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/ClassScanner.java	                        (rev 0)
+++ branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/ClassScanner.java	2009-06-21 17:24:30 UTC (rev 549)
@@ -0,0 +1,56 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.profiler.client.precompiler;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Class scanner
+ * @author Jesper Pedersen <jesper.pedersen at jboss.org>
+ */
+public class ClassScanner {
+
+  /**
+   * Constructor
+   */
+  private ClassScanner() {
+  }
+
+  /**
+   * Scan a directory for JAR files
+   * @param root The root directory
+    * @return The list of JAR files
+    */
+  public static List<File> scan(File root) {
+    try {
+      return ExtensionScanner.scan(root, ".class");
+    } catch (Exception e) {
+      System.err.println(e.getMessage());
+    }
+    
+    return null;
+  }
+}

Added: branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/ExtensionScanner.java
===================================================================
--- branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/ExtensionScanner.java	                        (rev 0)
+++ branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/ExtensionScanner.java	2009-06-21 17:24:30 UTC (rev 549)
@@ -0,0 +1,101 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.profiler.client.precompiler;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Extension scanner
+ * @author Jesper Pedersen <jesper.pedersen at jboss.org>
+ */
+public class ExtensionScanner {
+
+  /**
+   * Constructor
+   */
+  private ExtensionScanner() {
+  }
+
+  /**
+   * Scan a directory for files
+   * @param root The root directory
+   * @param extension The file extension
+   * @return The list of files
+   */
+  public static List<File> scan(File root, String extension) {
+    try {
+      return getFileListing(root, extension);
+    } catch (Exception e) {
+      System.err.println(e.getMessage());
+    }
+    
+    return null;
+  }
+  
+  
+  /**
+   * Recursively walk a directory tree and return a List of all
+   * Files found; the List is sorted using File.compareTo().
+   * @param aStartingDir is a valid directory, which can be read.
+   * @param extension The file extension
+   * @return The list of files
+   * @exception Exception Thrown if an error occurs
+   */
+  private static List<File> getFileListing(File aStartingDir, String extension) throws Exception {
+    List<File> result = getFileListingNoSort(aStartingDir, extension);
+    Collections.sort(result);
+    return result;
+  }
+  
+  /**
+   * Recursively walk a directory tree and return a List of all
+   * Files found; the List is sorted using File.compareTo().
+   * @param aStartingDir is a valid directory, which can be read.
+   * @param extension The file extension
+   * @return The list of files
+   * @exception Exception Thrown if an error occurs
+   */
+  private static List<File> getFileListingNoSort(File aStartingDir, String extension) throws Exception {
+    List<File> result = new ArrayList<File>();
+    
+    File[] filesAndDirs = aStartingDir.listFiles();
+    
+    List<File> filesDirs = Arrays.asList(filesAndDirs);
+    
+    for (File file : filesDirs) {
+      if (file.isFile()) {
+        if (file.getName().endsWith(extension)) {
+          result.add(file);
+        }
+      } else if (file.isDirectory()) {
+        List<File> deeperList = getFileListingNoSort(file, extension);
+        result.addAll(deeperList);
+      }
+    }
+
+    return result;
+  }
+}

Added: branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/FileUtil.java
===================================================================
--- branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/FileUtil.java	                        (rev 0)
+++ branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/FileUtil.java	2009-06-21 17:24:30 UTC (rev 549)
@@ -0,0 +1,91 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2007-2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.profiler.client.precompiler;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+
+/**
+ * An utility for files and directories
+ * @author <a href="mailto:jesper.pedersen at jboss.org">Jesper Pedersen</a>
+ */
+public class FileUtil {
+
+  /**
+   * Constructor
+   */
+  private FileUtil() {
+  }
+
+  /**
+   * Recursive delete
+   * @param f The file handler
+   */
+  public static void recursiveDelete(File f) {
+    if (f.exists()) {
+      File[] files = f.listFiles();
+      if (files != null) {
+        for (int i = 0; i < files.length; i++) {
+          if (files[i].isDirectory()) {
+            recursiveDelete(files[i]);
+          } else {
+            files[i].delete();
+          }
+        }
+      }
+      f.delete();
+    }
+  }
+
+  /**
+   * Copy file
+   * @param from The from file
+   * @param to The to file
+   * @exception Exception Thrown if an error occurs
+   */
+  public static void copyFile(File from, File to) throws Exception {
+    FileInputStream fis  = new FileInputStream(from);
+    BufferedInputStream bis = new BufferedInputStream(fis);
+    FileOutputStream fos = new FileOutputStream(to);
+    BufferedOutputStream bos = new BufferedOutputStream(fos);
+    try {
+      byte[] buf = new byte[4096];
+      int i = 0;
+      while ((i = bis.read(buf)) != -1) {
+        bos.write(buf, 0, i);
+      }
+      bos.flush();
+    } catch (Exception e) {
+      throw e;
+    } finally {
+      if (fis != null) {
+        fis.close();
+      }
+      if (fos != null) {
+        fos.close();
+      }
+    }
+  }
+}

Added: branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/JarScanner.java
===================================================================
--- branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/JarScanner.java	                        (rev 0)
+++ branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/JarScanner.java	2009-06-21 17:24:30 UTC (rev 549)
@@ -0,0 +1,56 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.profiler.client.precompiler;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Jar scanner
+ * @author Jesper Pedersen <jesper.pedersen at jboss.org>
+ */
+public class JarScanner {
+
+  /**
+   * Constructor
+   */
+  private JarScanner() {
+  }
+
+  /**
+   * Scan a directory for JAR files
+   * @param root The root directory
+    * @return The list of JAR files
+    */
+  public static List<File> scan(File root) {
+    try {
+      return ExtensionScanner.scan(root, ".jar");
+    } catch (Exception e) {
+      System.err.println(e.getMessage());
+    }
+    
+    return null;
+  }
+}

Added: branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/Precompiler.java
===================================================================
--- branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/Precompiler.java	                        (rev 0)
+++ branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/Precompiler.java	2009-06-21 17:24:30 UTC (rev 549)
@@ -0,0 +1,504 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2007-2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.profiler.client.precompiler;
+
+import org.jboss.profiler.shared.Version;
+import org.jboss.profiler.shared.Visibility;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+
+import org.jboss.logging.Logger;
+
+/**
+ * The precompiler tool
+ * @author Jesper Pedersen <jesper.pedersen at jboss.org>
+ */
+public class Precompiler {
+  /** The logger */
+  private static Logger log = Logger.getLogger(Precompiler.class);
+
+  /** Include all */
+  private static  boolean includeAll = false;
+
+  /** The include list */
+  private static  List<String> includeList = new ArrayList<String>();
+
+  /** Exclude all */
+  private static  boolean excludeAll = true;
+
+  /** The exclude list */
+  private static  List<String> excludeList = new ArrayList<String>();
+
+  /** Visibility tree */
+  private static  TreeMap visibilityTree;
+
+  /** Visibility */
+  private static  Visibility visibility;
+
+  /** Class pool */
+  private static ClassPool cp;
+
+  /** Instrumented count */
+  private static int instrumented;
+
+  /**
+   * Constructor
+   */
+  private Precompiler() {
+  }
+
+  /**
+   * Instrument
+   * @param include The include list
+   * @param exclude The exclude list
+   * @param vs The visibility setting
+   * @param f The file handler
+   * @exception Exception Thrown if an error occurs
+   */
+  private static void instrument(String include, String exclude, String vs, File f) throws Exception {
+    instrumented = 0;
+    initVisibility(vs);
+    initIncludeExclude(include, exclude);
+    initClassPool(f);
+
+    String tmpDirectoryLocation = System.getProperty("java.io.tmpdir");
+    File tmpDirectory = new File(tmpDirectoryLocation, "jboss-profiler-tmp");
+
+    if (tmpDirectory.exists()) {
+      FileUtil.recursiveDelete(tmpDirectory);
+    }
+
+    tmpDirectory.mkdirs();
+    tmpDirectory.deleteOnExit();
+
+    int archives = 0;
+
+    if (f.isDirectory()) {
+      List<File> jarFiles = JarScanner.scan(f);
+      archives = jarFiles.size();
+
+      if (jarFiles != null && jarFiles.size() > 0) {
+        for (File jarFile : jarFiles) {
+          log.info("Processing: " + jarFile.getAbsolutePath());
+
+          File extractedArchive = ArchiveUtil.extract(jarFile, tmpDirectory);
+          
+          boolean modified = false;
+          
+          List<File> classFiles = ClassScanner.scan(extractedArchive);
+          if (classFiles != null && classFiles.size() > 0) {
+            for (File classFile : classFiles) {
+              modified |= instrumentClass(classFile);
+            }
+          }
+          
+          if (modified) {
+            File newJarFile = new File(tmpDirectory, jarFile.getName() + "~");
+            ArchiveUtil.compress(extractedArchive, newJarFile);
+            
+            FileUtil.recursiveDelete(extractedArchive);
+            
+            if (!newJarFile.renameTo(jarFile)) {
+              try {
+                FileUtil.copyFile(newJarFile, jarFile);
+                FileUtil.recursiveDelete(newJarFile);
+              } catch (Exception e) {
+                log.error("Couldn't move " + newJarFile.getAbsolutePath() + " to " + jarFile.getAbsolutePath(), e);
+              }
+            }
+          } else {
+            FileUtil.recursiveDelete(extractedArchive);
+          }
+        }
+      }
+    } else {
+      log.info("Processing: " + f.getAbsolutePath());
+
+      File extractedArchive = ArchiveUtil.extract(f, tmpDirectory);
+          
+      boolean modified = false;
+      
+      List<File> classFiles = ClassScanner.scan(extractedArchive);
+      if (classFiles != null && classFiles.size() > 0) {
+        for (File classFile : classFiles) {
+          modified |= instrumentClass(classFile);
+        }
+      }
+      
+      if (modified) {
+        File newJarFile = new File(tmpDirectory, f.getName() + "~");
+        ArchiveUtil.compress(extractedArchive, newJarFile);
+        
+        FileUtil.recursiveDelete(extractedArchive);
+        
+        if (!newJarFile.renameTo(f)) {
+          try {
+            FileUtil.copyFile(newJarFile, f);
+            FileUtil.recursiveDelete(newJarFile);
+          } catch (Exception e) {
+            log.error("Couldn't move " + newJarFile.getAbsolutePath() + " to " + f.getAbsolutePath(), e);
+          }
+        }
+      } else {
+        FileUtil.recursiveDelete(extractedArchive);
+      }
+    }
+
+    log.info("Instrumented " + instrumented + " classes in " + archives + " archives.");
+  }
+
+  /**
+   * Instrument class
+   * @param file The class file
+   * @return True if the class was modified; otherwise false
+   * @exception Exception Thrown if an error occurs
+   */
+  private static boolean instrumentClass(File file) throws Exception {
+    FileInputStream fis = new FileInputStream(file);
+    BufferedInputStream bis = new BufferedInputStream(fis);
+
+    CtClass ctClass = cp.makeClass(bis, false);
+
+    bis.close();
+
+    String ctClassSlashName = ctClass.getName().replace('.', '/');
+    if (accept(ctClassSlashName)) {
+      Visibility v = getVisibility(ctClassSlashName);
+      try {
+        byte[] b = ClassInstrumenter.instrument(ctClass, v);
+
+        if (b != null && b.length > 0) {
+          FileOutputStream fos = null;
+          try {
+            fos = new FileOutputStream(file);
+            BufferedOutputStream bos = new BufferedOutputStream(fos, 16384);
+            
+            bos.write(b);
+            
+            bos.flush();
+          } finally {
+            if (fos != null) {
+              try {
+                fos.close();
+              } catch (IOException ioe) {
+                // Ignore
+              }
+            }
+          }
+
+          log.debug("Instrumented: " + ctClass.getName());
+
+          instrumented++;
+          return true;
+        }
+      } catch (Throwable t) {
+        log.warn("Can't precompile: " + ctClass.getName());
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Init class pool
+   * @param f The file handler
+   * @exception Exception Thrown if an error occurs
+   */
+  private static void initClassPool(File f) throws Exception {
+    cp = ClassPool.getDefault();
+
+    if (f.isDirectory()) {
+      Set<String> s = new HashSet<String>();
+    
+      List<File> jarFiles = JarScanner.scan(f);
+
+      if (jarFiles != null && jarFiles.size() > 0) {
+        for (File jarFile : jarFiles) {
+          if (!s.contains(jarFile.getName())) {
+            cp.appendClassPath(jarFile.getAbsolutePath());
+            s.add(jarFile.getName());
+          }
+        }
+      }
+    } else {
+      cp.appendClassPath(f.getAbsolutePath());
+    }
+  }
+
+  /**
+   * Init visibility
+   */
+  private static void initVisibility(String vs) {
+    visibility = parseVisibility(vs);
+    visibilityTree = new TreeMap(new SizeComparator());
+  }
+
+  /**
+   * Parse visibility property
+   * @param vs The property
+   * @return The visibility
+   */
+  private static Visibility parseVisibility(String vs) {
+    log.debug("Visibility=" + vs);
+
+    if (vs != null) {
+      if ("public".equalsIgnoreCase(vs)) {
+        return Visibility.PUBLIC;
+      } else if ("package".equalsIgnoreCase(vs)) {
+        return Visibility.PACKAGE;
+      } else if ("protected".equalsIgnoreCase(vs)) {
+        return Visibility.PROTECTED;
+      }
+    }
+    return Visibility.PRIVATE;
+  }
+  
+  /**
+   * Init include / exclude
+   * @param include The includes
+   * @param exclude The excludes
+   */
+  private static void initIncludeExclude(String include, String exclude) {
+    log.debug("Includes=" + include);
+    log.debug("Excludes=" + exclude);
+
+    if (include != null) {
+      StringTokenizer st = new StringTokenizer(include, ",");
+      List<String> l = new ArrayList<String>();
+      while (st.hasMoreTokens()) {
+        String s = st.nextToken();
+        s = s.trim();
+        if ("*".equals(s)) {
+          includeAll = true;
+        } else {
+          l.add(s);
+        }
+      }
+      Collections.sort(l, new SizeComparator());
+      Collections.reverse(l);
+
+      for (String s : l) {
+        String c = s;
+        String v = null;
+        if (s.indexOf("|") != -1) {
+          c = s.substring(0, s.indexOf("|"));
+          c = c.trim();
+          v = s.substring(s.indexOf("|") + 1);
+          v = v.trim();
+        }
+        
+        if (c.endsWith(".*")) {
+          c = c.substring(0, c.indexOf(".*")) + "/";
+        }
+        if (c.endsWith(".class")) {
+          c = c.substring(0, c.indexOf(".class"));
+        }
+        c = c.replace('.', '/');
+        
+        Iterator it = includeList.iterator();
+        while (it.hasNext()) {
+          String t = (String)it.next();
+          
+          if (t.startsWith(c)) {
+            it.remove();
+          }
+        }
+        it = visibilityTree.keySet().iterator();
+        while (it.hasNext()) {
+          String t = (String)it.next();
+          
+          if (t.startsWith(c)) {
+            it.remove();
+          }
+        }
+        
+        includeList.add(c);
+        if (v != null) {
+          visibilityTree.put(c, parseVisibility(v));
+        }
+      }
+    }
+
+    if (exclude != null) {
+      excludeAll = false;
+      StringTokenizer st = new StringTokenizer(exclude, ",");
+      List<String> l = new ArrayList<String>();
+      while (st.hasMoreTokens()) {
+        String s = st.nextToken();
+        s = s.trim();
+        if ("*".equals(s)) {
+          excludeAll = true;
+        } else {
+          l.add(s);
+        }
+      }
+      Collections.sort(l, new SizeComparator());
+
+      for (String c : l) {
+        if (c.endsWith(".*")) {
+          c = c.substring(0, c.indexOf(".*")) + "/";
+        }
+        if (c.endsWith(".class")) {
+          c = c.substring(0, c.indexOf(".class"));
+        }
+        c = c.replace('.', '/');
+
+        Iterator it = excludeList.iterator();
+        while (it.hasNext()) {
+          String s = (String)it.next();
+          
+          if (s.startsWith(c)) {
+            it.remove();
+          }
+        }
+        
+        excludeList.add(c);
+      }
+    }
+
+    Collections.sort(includeList, new SizeComparator());
+    Collections.sort(excludeList, new SizeComparator());
+  }
+
+  /**
+   * Approve the following class for transformation
+   * @param className The class name
+   * @return True if the class is approved; otherwise false
+   */
+  private static boolean approve(String className) {
+    // We can't profile the profiler, Java / Sun classes 
+    // nor Javassist
+    if (className.startsWith("org/jboss/profiler/agent/") ||
+        className.startsWith("org/jboss/profiler/as/") ||
+        className.startsWith("org/jboss/profiler/client/") ||
+        className.startsWith("org/jboss/profiler/connectors/") ||
+        className.startsWith("org/jboss/profiler/plugins/") ||
+        className.startsWith("org/jboss/profiler/shared/") ||
+        className.startsWith("java/") ||
+        className.startsWith("javax/") ||
+        className.startsWith("sun/") ||
+        className.startsWith("com/sun/") ||
+        className.startsWith("javassist/")) {
+      return false;
+    }
+
+    return true;
+  }
+
+  /**
+   * Accept the following class for transformation
+   * @param className The class name
+   * @return True if the class should be transformed; otherwise false
+   */
+  public static boolean accept(String className) {
+    if (!approve(className)) {
+      return false;
+    }
+
+    for (String cl : excludeList) {
+      if (className.startsWith(cl)) {
+        return false;
+      }
+    }
+
+    if (includeAll && !excludeAll) {
+      return true;
+    }
+
+    for (String cl : includeList) {
+      if (className.startsWith(cl)) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  /**
+   * Get the visibility for class
+   * @param className The class name
+   * @return The visibility
+   */
+  private static Visibility getVisibility(String className) {
+    Iterator it = visibilityTree.entrySet().iterator();
+    while (it.hasNext()) {
+      Map.Entry entry = (Map.Entry)it.next();
+      String key = (String)entry.getKey();
+      if (className.startsWith(key)) {
+        return (Visibility)entry.getValue();
+      }
+    }
+
+    return visibility;
+  }
+
+  /**
+   * The main method
+   * @param args The arguments
+   */
+  public static void main(String[] args) {
+    if (args.length == 4) {
+      try {
+        log.info(Version.VENDOR + " Profiler Precompiler " + Version.VERSION);
+
+        String include = args[0];
+        String exclude = args[1];
+        String vs = args[2];
+        File f = new File(args[3]);
+
+        if (f.exists()) {
+          Precompiler.instrument(include, exclude, vs, f);
+        } else {
+          log.fatal("Can't locate " + f.getAbsolutePath());
+        }
+
+      } catch (Throwable t) {
+        t.printStackTrace(System.err);
+      }
+    } else {
+      usage();
+    }
+  }
+
+  /**
+   * The usage method
+   */
+  private static void usage() {
+    System.out.println("Usage: Precompiler <includes> <excludes> <visibility> <directory>");
+  }
+}

Added: branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/SizeComparator.java
===================================================================
--- branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/SizeComparator.java	                        (rev 0)
+++ branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/SizeComparator.java	2009-06-21 17:24:30 UTC (rev 549)
@@ -0,0 +1,48 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2007-2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.profiler.client.precompiler;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+/**
+ * Size comparator
+ * @author Jesper Pedersen <jesper.pedersen at jboss.org>
+ */
+public class SizeComparator implements Comparator<String>, Serializable {
+
+  /**
+   * Compare two objects
+   * @param sa String
+   * @param sb String
+   * @return Positive if sb greater than sa; zero if equal; otherwise negative
+   */
+  public int compare(String sa, String sb) {
+    if (sa.length() < sb.length()) {
+      return 1;
+    } else if (sa.length() == sb.length()) { 
+      return sa.compareTo(sb);
+    } else {
+      return -1;
+    }
+  }
+}

Added: branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/package.html
===================================================================
--- branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/package.html	                        (rev 0)
+++ branches/JBossProfiler2/src/main/org/jboss/profiler/client/precompiler/package.html	2009-06-21 17:24:30 UTC (rev 549)
@@ -0,0 +1,4 @@
+<body>
+The precompiler injects profiling information into JAR files, so they don't
+have to be instrumented during startup.
+</body>

Modified: branches/JBossProfiler2/src/main/org/jboss/profiler/shared/ClassInfo.java
===================================================================
--- branches/JBossProfiler2/src/main/org/jboss/profiler/shared/ClassInfo.java	2009-06-16 01:51:25 UTC (rev 548)
+++ branches/JBossProfiler2/src/main/org/jboss/profiler/shared/ClassInfo.java	2009-06-21 17:24:30 UTC (rev 549)
@@ -87,4 +87,13 @@
   public int hashCode() {
     return className.hashCode();
   }
+
+  /**
+   * Get the string representation
+   * @return The string
+   */
+  @Override
+  public String toString() {
+    return className + "," + classType;
+  }
 }

Modified: branches/JBossProfiler2/src/main/org/jboss/profiler/shared/MethodInfo.java
===================================================================
--- branches/JBossProfiler2/src/main/org/jboss/profiler/shared/MethodInfo.java	2009-06-16 01:51:25 UTC (rev 548)
+++ branches/JBossProfiler2/src/main/org/jboss/profiler/shared/MethodInfo.java	2009-06-21 17:24:30 UTC (rev 549)
@@ -88,4 +88,13 @@
   public int hashCode() {
     return methodName.hashCode() + className.hashCode();
   }
+
+  /**
+   * Get the string representation
+   * @return The string
+   */
+  @Override
+  public String toString() {
+    return methodName + "," + className;
+  }
 }




More information about the jboss-cvs-commits mailing list