View Javadoc

    1   /***************************************************************************************
    2    * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved.                 *
    3    * http://aspectwerkz.codehaus.org                                                    *
    4    * ---------------------------------------------------------------------------------- *
    5    * The software in this package is published under the terms of the LGPL license      *
    6    * a copy of which has been included with this distribution in the license.txt file.  *
    7    **************************************************************************************/
    8   package org.codehaus.aspectwerkz.hook;
    9
    10  import java.io.File;
    11  import java.io.FileOutputStream;
    12  import java.util.HashMap;
    13  import java.util.Map;
    14  import java.util.StringTokenizer;
    15  import java.util.jar.Attributes;
    16  import java.util.jar.JarOutputStream;
    17  import java.util.jar.Manifest;
    18  import java.util.zip.CRC32;
    19  import java.util.zip.ZipEntry;
    20  import java.lang.reflect.Method;
    21
    22  /***
    23   * Main application that allow two steps preparation of the hook <p/>This can be used instead of ProcessStarter to dual
    24   * JVM and stream piping <br/><p/>
    25   * <h2>Usage</h2>
    26   * <pre>
    27   *     java [options..] org.codehaus.aspectwerkz.hook.Plug -target &lt;targetJar.jar&gt;
    28   *     java [options..] org.codehaus.aspectwerkz.hook.Plug -hotswap &lt;jdwp options&gt;
    29   *     java [options..] org.codehaus.aspectwerkz.hook.Plug -resume &lt;jdwp options&gt;
    30   *     java [options..] org.codehaus.aspectwerkz.hook.Plug -info &lt;jdwp options&gt;
    31   * </pre>
    32   * <p/>
    33   * <ul>
    34   * <li>-target targetJar.jar to generate a targetJar.jar containing the patched java.lang.ClassLoader suitable for your
    35   * current java installation. <br/>Add this jar in -Xbootclasspath/p: options as other AspectWerkz options [see
    36   * documentation]</li>
    37   * <li>-hotswap will hotswap the java.lang.ClassLoader in a running or suspended jvm, and will resume the jvm</li>
    38   * <li>-resume will resume the (running or) suspended jvm</li>
    39   * <li>-info will print out JPDA information and resume the (running or) suspended jvm</li>*
    40   * </ul>
    41   * For the last two invocations, [jdwp options] must be the subpart of the -Xrunjdwp option indicating how to connect to
    42   * the remote JVM (see sample below or documentation). <i>For now, only localhost connection is supported. </i>
    43   * <p/>
    44   * If the JVM was started with -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y
    45   * Use java [options..] ..Plug -prepare transport=dt_socket,address=8000
    46   * <p/>
    47   * <b>Be sure to set AspectWerkz option prior to starting the JVM with -Xrunjdwp options. </b>
    48   *
    49   * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
    50   */
    51  public class Plug {
    52
    53      /***
    54       * Dumps the modified java.lang.ClassLoader in destJar
    55       * The aspectcwerkz.classloader.clclasspreprocessor is used
    56       * if specified, else defaults to AspectWerkz layer 1
    57       *
    58       * @param destJar
    59       * @throws Exception
    60       */
    61      public void target(String destJar) throws Exception {
    62          File dest = new File(destJar);
    63          if (dest.exists() && !dest.canWrite()) {
    64              throw new Exception(destJar + " exists and is not writable");
    65          }
    66
    67          // patch the java.lang.ClassLoader
    68          byte[] patched = ClassLoaderPatcher.getPatchedClassLoader(
    69                  System.getProperty(
    70                          ProcessStarter.CL_PRE_PROCESSOR_CLASSNAME_PROPERTY,
    71                          org.codehaus.aspectwerkz.hook.impl.ClassLoaderPreProcessorImpl.class.getName()
    72                  )
    73          );
    74
    75          // pack the jar file
    76          Manifest mf = new Manifest();
    77          Attributes at = mf.getMainAttributes();
    78          at.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0");
    79          at.putValue("Created-By", "AspectWerkz (c) Plug [java " + System.getProperty("java.version") + ']');
    80          ZipEntry entry = new ZipEntry("java/lang/ClassLoader.class");
    81          entry.setSize(patched.length);
    82          CRC32 crc = new CRC32();
    83          crc.update(patched);
    84          entry.setCrc(crc.getValue());
    85          JarOutputStream jar = new JarOutputStream(new FileOutputStream(dest), mf);
    86          jar.putNextEntry(entry);
    87          jar.write(patched);
    88          jar.closeEntry();
    89          jar.close();
    90      }
    91
    92
    93      /***
    94       * Print usage information on stdout
    95       */
    96      public static void usage() {
    97          System.out.println("AspectWerkz (c) Plug");
    98          System.out.println("Usage: " + "-target <targetJar.jar>");
    99          System.out.println("       " + "-hotswap <jdwp options>");
    100         System.out.println("       " + "-resume <jdwp options>");
    101         System.out.println("       " + "-info <jdwp options>");
    102     }
    103
    104     /***
    105      * Parse a jdwp like string in a Map <p/>transport=dt_socket,address=8000 will produce a Map of 2 entries whose keys
    106      * are transport and address
    107      *
    108      * @param args
    109      * @return Map jdwp options
    110      */
    111     public static Map parseArgs(String args) throws Exception {
    112         Map map = new HashMap();
    113         StringTokenizer st = new StringTokenizer(args, ",");
    114         while (st.hasMoreTokens()) {
    115             String token = st.nextToken();
    116             int index = token.indexOf("=");
    117             if (index < 0) {
    118                 throw new Exception("invalid jdwp string: " + args);
    119             }
    120             map.put(token.substring(0, index), token.substring(index + 1));
    121         }
    122         return map;
    123     }
    124
    125     public static void main(String[] args) {
    126         if (args.length != 2) {
    127             usage();
    128             System.exit(1);
    129         }
    130         if ("-target".equals(args[0])) {
    131             try {
    132                 new Plug().target(args[1]);
    133                 System.out.println("done: " + args[1]);
    134             } catch (Exception e) {
    135                 System.err.println("-target failed: " + e.getMessage());
    136                 e.printStackTrace();
    137             }
    138         } else {
    139             try {
    140                 Map jdwp = parseArgs(args[1]);
    141                 // do a reflect invocation to avoid relying on a tools.jar dependancy
    142                 if ("-hotswap".equals(args[0])) {
    143                     Class jdwpClass = Class.forName(
    144                             "org.codehaus.aspectwerkz.hook.JDWPPlug", false, Plug.class.getClassLoader()
    145                     );
    146                     Object instance = jdwpClass.newInstance();
    147                     Method m = jdwpClass.getDeclaredMethod("hotswap", new Class[]{Map.class});
    148                     m.invoke(instance, new Object[]{jdwp});
    149                     //new JDWPPlug().hotswap(jdwp);
    150                 } else if ("-resume".equals(args[0])) {
    151                     Class jdwpClass = Class.forName(
    152                             "org.codehaus.aspectwerkz.hook.JDWPPlug", false, Plug.class.getClassLoader()
    153                     );
    154                     Object instance = jdwpClass.newInstance();
    155                     Method m = jdwpClass.getDeclaredMethod("resume", new Class[]{Map.class});
    156                     m.invoke(instance, new Object[]{jdwp});
    157                     //new JDWPPlug().resume(jdwp);
    158                 } else if ("-info".equals(args[0])) {
    159                     Class jdwpClass = Class.forName(
    160                             "org.codehaus.aspectwerkz.hook.JDWPPlug", false, Plug.class.getClassLoader()
    161                     );
    162                     Object instance = jdwpClass.newInstance();
    163                     Method m = jdwpClass.getDeclaredMethod("info", new Class[]{Map.class});
    164                     m.invoke(instance, new Object[]{jdwp});
    165                     //new JDWPPlug().info(jdwp);
    166                 } else {
    167                     usage();
    168                     System.exit(1);
    169                 }
    170             } catch (Exception e) {
    171                 System.err.println(args[0] + " failed: " + e.getMessage());
    172                 e.printStackTrace();
    173             }
    174         }
    175     }
    176 }