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 <targetJar.jar>
28 * java [options..] org.codehaus.aspectwerkz.hook.Plug -hotswap <jdwp options>
29 * java [options..] org.codehaus.aspectwerkz.hook.Plug -resume <jdwp options>
30 * java [options..] org.codehaus.aspectwerkz.hook.Plug -info <jdwp options>
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
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
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
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
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
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
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 }