/************************************************************************************** * Copyright (c) Jonas Bon�r, Alexandre Vasseur. All rights reserved. * * http://aspectwerkz.codehaus.org * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the LGPL license * * a copy of which has been included with this distribution in the license.txt file. * **************************************************************************************/ package org.codehaus.aspectwerkz.hook; import java.io.File; import java.io.FileOutputStream; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; import java.util.jar.Attributes; import java.util.jar.JarOutputStream; import java.util.jar.Manifest; import java.util.zip.CRC32; import java.util.zip.ZipEntry; import java.lang.reflect.Method; /** * Main application that allow two steps preparation of the hook <p/>This can be used instead of ProcessStarter to dual * JVM and stream piping <br/><p/> * <h2>Usage</h2> * <pre> * java [options..] org.codehaus.aspectwerkz.hook.Plug -target <targetJar.jar> * java [options..] org.codehaus.aspectwerkz.hook.Plug -hotswap <jdwp options> * java [options..] org.codehaus.aspectwerkz.hook.Plug -resume <jdwp options> * java [options..] org.codehaus.aspectwerkz.hook.Plug -info <jdwp options> * </pre> * <p/> * <ul> * <li>-target targetJar.jar to generate a targetJar.jar containing the patched java.lang.ClassLoader suitable for your * current java installation. <br/>Add this jar in -Xbootclasspath/p: options as other AspectWerkz options [see * documentation]</li> * <li>-hotswap will hotswap the java.lang.ClassLoader in a running or suspended jvm, and will resume the jvm</li> * <li>-resume will resume the (running or) suspended jvm</li> * <li>-info will print out JPDA information and resume the (running or) suspended jvm</li>* * </ul> * For the last two invocations, [jdwp options] must be the subpart of the -Xrunjdwp option indicating how to connect to * the remote JVM (see sample below or documentation). <i>For now, only localhost connection is supported. </i> * <p/> * If the JVM was started with -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y * Use java [options..] ..Plug -prepare transport=dt_socket,address=8000 * <p/> * <b>Be sure to set AspectWerkz option prior to starting the JVM with -Xrunjdwp options. </b> * * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a> */ public class Plug { /** * Dumps the modified java.lang.ClassLoader in destJar * The aspectcwerkz.classloader.clclasspreprocessor is used * if specified, else defaults to AspectWerkz layer 1 * * @param destJar * @throws Exception */ public void target(String destJar) throws Exception { File dest = new File(destJar); if (dest.exists() && !dest.canWrite()) { throw new Exception(destJar + " exists and is not writable"); } // patch the java.lang.ClassLoader byte[] patched = ClassLoaderPatcher.getPatchedClassLoader( System.getProperty( ProcessStarter.CL_PRE_PROCESSOR_CLASSNAME_PROPERTY, org.codehaus.aspectwerkz.hook.impl.ClassLoaderPreProcessorImpl.class.getName() ) ); // pack the jar file Manifest mf = new Manifest(); Attributes at = mf.getMainAttributes(); at.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0"); at.putValue("Created-By", "AspectWerkz (c) Plug [java " + System.getProperty("java.version") + ']'); ZipEntry entry = new ZipEntry("java/lang/ClassLoader.class"); entry.setSize(patched.length); CRC32 crc = new CRC32(); crc.update(patched); entry.setCrc(crc.getValue()); JarOutputStream jar = new JarOutputStream(new FileOutputStream(dest), mf); jar.putNextEntry(entry); jar.write(patched); jar.closeEntry(); jar.close(); } /** * Print usage information on stdout */ public static void usage() { System.out.println("AspectWerkz (c) Plug"); System.out.println("Usage: " + "-target <targetJar.jar>"); System.out.println(" " + "-hotswap <jdwp options>"); System.out.println(" " + "-resume <jdwp options>"); System.out.println(" " + "-info <jdwp options>"); } /** * Parse a jdwp like string in a Map <p/>transport=dt_socket,address=8000 will produce a Map of 2 entries whose keys * are transport and address * * @param args * @return Map jdwp options */ public static Map parseArgs(String args) throws Exception { Map map = new HashMap(); StringTokenizer st = new StringTokenizer(args, ","); while (st.hasMoreTokens()) { String token = st.nextToken(); int index = token.indexOf("="); if (index < 0) { throw new Exception("invalid jdwp string: " + args); } map.put(token.substring(0, index), token.substring(index + 1)); } return map; } public static void main(String[] args) { if (args.length != 2) { usage(); System.exit(1); } if ("-target".equals(args[0])) { try { new Plug().target(args[1]); System.out.println("done: " + args[1]); } catch (Exception e) { System.err.println("-target failed: " + e.getMessage()); e.printStackTrace(); } } else { try { Map jdwp = parseArgs(args[1]); // do a reflect invocation to avoid relying on a tools.jar dependancy if ("-hotswap".equals(args[0])) { Class jdwpClass = Class.forName( "org.codehaus.aspectwerkz.hook.JDWPPlug", false, Plug.class.getClassLoader() ); Object instance = jdwpClass.newInstance(); Method m = jdwpClass.getDeclaredMethod("hotswap", new Class[]{Map.class}); m.invoke(instance, new Object[]{jdwp}); //new JDWPPlug().hotswap(jdwp); } else if ("-resume".equals(args[0])) { Class jdwpClass = Class.forName( "org.codehaus.aspectwerkz.hook.JDWPPlug", false, Plug.class.getClassLoader() ); Object instance = jdwpClass.newInstance(); Method m = jdwpClass.getDeclaredMethod("resume", new Class[]{Map.class}); m.invoke(instance, new Object[]{jdwp}); //new JDWPPlug().resume(jdwp); } else if ("-info".equals(args[0])) { Class jdwpClass = Class.forName( "org.codehaus.aspectwerkz.hook.JDWPPlug", false, Plug.class.getClassLoader() ); Object instance = jdwpClass.newInstance(); Method m = jdwpClass.getDeclaredMethod("info", new Class[]{Map.class}); m.invoke(instance, new Object[]{jdwp}); //new JDWPPlug().info(jdwp); } else { usage(); System.exit(1); } } catch (Exception e) { System.err.println(args[0] + " failed: " + e.getMessage()); e.printStackTrace(); } } } }