001: /**************************************************************************************
002: * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved. *
003: * http://aspectwerkz.codehaus.org *
004: * ---------------------------------------------------------------------------------- *
005: * The software in this package is published under the terms of the LGPL license *
006: * a copy of which has been included with this distribution in the license.txt file. *
007: **************************************************************************************/package org.codehaus.aspectwerkz.hook;
008:
009: import java.io.File;
010: import java.io.FileOutputStream;
011: import java.util.HashMap;
012: import java.util.Map;
013: import java.util.StringTokenizer;
014: import java.util.jar.Attributes;
015: import java.util.jar.JarOutputStream;
016: import java.util.jar.Manifest;
017: import java.util.zip.CRC32;
018: import java.util.zip.ZipEntry;
019: import java.lang.reflect.Method;
020:
021: /**
022: * Main application that allow two steps preparation of the hook <p/>This can be used instead of ProcessStarter to dual
023: * JVM and stream piping <br/><p/>
024: * <h2>Usage</h2>
025: * <pre>
026: * java [options..] org.codehaus.aspectwerkz.hook.Plug -target <targetJar.jar>
027: * java [options..] org.codehaus.aspectwerkz.hook.Plug -hotswap <jdwp options>
028: * java [options..] org.codehaus.aspectwerkz.hook.Plug -resume <jdwp options>
029: * java [options..] org.codehaus.aspectwerkz.hook.Plug -info <jdwp options>
030: * </pre>
031: * <p/>
032: * <ul>
033: * <li>-target targetJar.jar to generate a targetJar.jar containing the patched java.lang.ClassLoader suitable for your
034: * current java installation. <br/>Add this jar in -Xbootclasspath/p: options as other AspectWerkz options [see
035: * documentation]</li>
036: * <li>-hotswap will hotswap the java.lang.ClassLoader in a running or suspended jvm, and will resume the jvm</li>
037: * <li>-resume will resume the (running or) suspended jvm</li>
038: * <li>-info will print out JPDA information and resume the (running or) suspended jvm</li>*
039: * </ul>
040: * For the last two invocations, [jdwp options] must be the subpart of the -Xrunjdwp option indicating how to connect to
041: * the remote JVM (see sample below or documentation). <i>For now, only localhost connection is supported. </i>
042: * <p/>
043: * If the JVM was started with -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y
044: * Use java [options..] ..Plug -prepare transport=dt_socket,address=8000
045: * <p/>
046: * <b>Be sure to set AspectWerkz option prior to starting the JVM with -Xrunjdwp options. </b>
047: *
048: * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
049: */
050: public class Plug {
051:
052: /**
053: * Dumps the modified java.lang.ClassLoader in destJar
054: * The aspectcwerkz.classloader.clclasspreprocessor is used
055: * if specified, else defaults to AspectWerkz layer 1
056: *
057: * @param destJar
058: * @throws Exception
059: */
060: public void target(String destJar) throws Exception {
061: File dest = new File(destJar);
062: if (dest.exists() && !dest.canWrite()) {
063: throw new Exception(destJar + " exists and is not writable");
064: }
065:
066: // patch the java.lang.ClassLoader
067: byte[] patched = ClassLoaderPatcher
068: .getPatchedClassLoader(System
069: .getProperty(
070: ProcessStarter.CL_PRE_PROCESSOR_CLASSNAME_PROPERTY,
071: org.codehaus.aspectwerkz.hook.impl.ClassLoaderPreProcessorImpl.class
072: .getName()));
073:
074: // pack the jar file
075: Manifest mf = new Manifest();
076: Attributes at = mf.getMainAttributes();
077: at.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0");
078: at.putValue("Created-By", "AspectWerkz (c) Plug [java "
079: + System.getProperty("java.version") + ']');
080: ZipEntry entry = new ZipEntry("java/lang/ClassLoader.class");
081: entry.setSize(patched.length);
082: CRC32 crc = new CRC32();
083: crc.update(patched);
084: entry.setCrc(crc.getValue());
085: JarOutputStream jar = new JarOutputStream(new FileOutputStream(
086: dest), mf);
087: jar.putNextEntry(entry);
088: jar.write(patched);
089: jar.closeEntry();
090: jar.close();
091: }
092:
093: /**
094: * Print usage information on stdout
095: */
096: public static void usage() {
097: System.out.println("AspectWerkz (c) Plug");
098: System.out.println("Usage: " + "-target <targetJar.jar>");
099: 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
121: .substring(index + 1));
122: }
123: return map;
124: }
125:
126: public static void main(String[] args) {
127: if (args.length != 2) {
128: usage();
129: System.exit(1);
130: }
131: if ("-target".equals(args[0])) {
132: try {
133: new Plug().target(args[1]);
134: System.out.println("done: " + args[1]);
135: } catch (Exception e) {
136: System.err.println("-target failed: " + e.getMessage());
137: e.printStackTrace();
138: }
139: } else {
140: try {
141: Map jdwp = parseArgs(args[1]);
142: // do a reflect invocation to avoid relying on a tools.jar dependancy
143: if ("-hotswap".equals(args[0])) {
144: Class jdwpClass = Class.forName(
145: "org.codehaus.aspectwerkz.hook.JDWPPlug",
146: false, Plug.class.getClassLoader());
147: Object instance = jdwpClass.newInstance();
148: Method m = jdwpClass.getDeclaredMethod("hotswap",
149: new Class[] { Map.class });
150: m.invoke(instance, new Object[] { jdwp });
151: //new JDWPPlug().hotswap(jdwp);
152: } else if ("-resume".equals(args[0])) {
153: Class jdwpClass = Class.forName(
154: "org.codehaus.aspectwerkz.hook.JDWPPlug",
155: false, Plug.class.getClassLoader());
156: Object instance = jdwpClass.newInstance();
157: Method m = jdwpClass.getDeclaredMethod("resume",
158: new Class[] { Map.class });
159: m.invoke(instance, new Object[] { jdwp });
160: //new JDWPPlug().resume(jdwp);
161: } else if ("-info".equals(args[0])) {
162: Class jdwpClass = Class.forName(
163: "org.codehaus.aspectwerkz.hook.JDWPPlug",
164: false, Plug.class.getClassLoader());
165: Object instance = jdwpClass.newInstance();
166: Method m = jdwpClass.getDeclaredMethod("info",
167: new Class[] { Map.class });
168: m.invoke(instance, new Object[] { jdwp });
169: //new JDWPPlug().info(jdwp);
170: } else {
171: usage();
172: System.exit(1);
173: }
174: } catch (Exception e) {
175: System.err.println(args[0] + " failed: "
176: + e.getMessage());
177: e.printStackTrace();
178: }
179: }
180: }
181: }
|