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 }