All Downloads are FREE. Search and download functionalities are using the official Maven repository.

kilim.tools.Weaver Maven / Gradle / Ivy

Go to download

Coroutines, continuations, fibers, actors and message passing for the JVM

There is a newer version: 2.0.2-jdk7
Show newest version
/* Copyright (c) 2006, Sriram Srinivasan, 2016 nqzero
 *
 * You may distribute this software under the terms of the license 
 * specified in the file "License"
 */

package kilim.tools;

import kilim.analysis.KilimContext;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import kilim.KilimException;
import kilim.WeavingClassLoader;
import kilim.analysis.ClassInfo;
import kilim.analysis.ClassWeaver;
import kilim.analysis.FileLister;
import kilim.mirrors.CachedClassMirrors;

/**
 * This class supports both command-line and run time weaving of Kilim bytecode. 
 */

public class Weaver {
    public static String outputDir = null;
    public static boolean verbose = true;
    public static boolean force = false;
    public static boolean proxy = true;
    public static Pattern excludePattern = null;
    static int err = 0;

    public KilimContext context;
    public Weaver(KilimContext $context) {
        context = $context==null ? new KilimContext() : $context;
    }
    
    
    
    
    /**
     * 
     * Usage: java kilim.tools.Weaver -d <output directory> {source classe, jar, directory ...}
     * 
* * If directory names or jar files are given, all classes in that container are processed. It is * perfectly fine to specify the same directory for source and output like this: *
     *    java kilim.tools.Weaver -d ./classes ./classes
     * 
* * by default, each element is added to the classpath (use -c to suppress classpath augmentation) * * arguments: *
    *
  • -d directory: write output to directory (required)
  • *
  • -f: force, write output even if output file is newer than source
  • *
  • -c: don't add source class list to the classpath
  • *
  • -h: print help info
  • *
  • -q: quiet
  • *
  • -x regex: exclude, skip classes matching regex
  • *
* * Ensure that all classes to be woven are in the classpath. The output directory does not have to be * in the classpath during weaving. * * @see #weave(List) for run-time weaving. */ public static void main(String[] args) throws IOException { ArrayList names = parseArgs(args); doMain(names.toArray(new String [] {}),null); if (err > 0) System.exit(err); } private static String [] concat(String [] a,String [] b) { String [] c = new String[a.length + b.length]; System.arraycopy(a,0,c,0,a.length); System.arraycopy(b,0,c,a.length,b.length); return c; } public static int doMain(String [] names,String [] classpath) throws IOException { mkdir(outputDir); Weaver weaver; if (proxy) { ClassLoader current = Weaver.class.getClassLoader(); String [] composite = classpath==null ? names : concat(names,classpath); URL [] paths = WeavingClassLoader.getURLs(composite); CachedClassMirrors ccm = new CachedClassMirrors(new URLClassLoader(paths,current)); weaver = new Weaver(new KilimContext(ccm)); } else weaver = new Weaver(null); String currentName = null; for (String name : names) { try { if (name.endsWith(".class")) { if (exclude(name)) continue; currentName = name; weaver.weaveFile(name, new BufferedInputStream(new FileInputStream(name))); } else if (name.endsWith(".jar")) { for (FileLister.Entry fe : new FileLister(name)) { currentName = fe.getFileName(); if (currentName.endsWith(".class")) { currentName = currentName.substring(0, currentName.length() - 6) .replace('/', '.'); if (exclude(currentName)) continue; weaver.weaveFile(currentName, fe.getInputStream()); } } } else if (new File(name).isDirectory()) { for (FileLister.Entry fe : new FileLister(name)) { currentName = fe.getFileName(); if (currentName.endsWith(".class")) { if (exclude(currentName)) continue; if (!force && fe.check(outputDir)) continue; weaver.weaveFile(currentName, fe.getInputStream()); } } } else { System.out.println("skipping class (support removed): " + name); } } catch (KilimException ke) { System.err.println("Error weaving " + currentName + ". " + ke.getMessage()); // ke.printStackTrace(); System.exit(1); } catch (IOException ioe) { System.err.println("Unable to find/process '" + currentName + "'"); System.exit(1); } catch (Throwable t) { System.err.println("Error weaving " + currentName); t.printStackTrace(); System.exit(1); } } return err; } static boolean exclude(String name) { return excludePattern == null ? false : excludePattern.matcher(name).find(); } // non-static to allow easy usage from alternative classloaders public ClassWeaver weave(InputStream is) { ClassWeaver cw = null; if (is==null) return null; try { cw = new ClassWeaver(context,is); cw.weave(); if (outputDir != null) writeClasses(cw); } catch (IOException ex) {} return cw; } public void weaveFile(String name, InputStream is) throws IOException { try { ClassWeaver cw = new ClassWeaver(context,is); cw.weave(); writeClasses(cw); } catch (KilimException ke) { System.err.println("***** Error weaving " + name + ". " + ke.getMessage()); // ke.printStackTrace(); err = 1; } catch (RuntimeException re) { System.err.println("***** Error weaving " + name + ". " + re.getMessage()); re.printStackTrace(); err = 1; } catch (IOException ioe) { err = 1; System.err.println("***** Unable to find/process '" + name + "'\n" + ioe.getMessage()); } } static void writeClasses(ClassWeaver cw) throws IOException { List cis = cw.getClassInfos(); if (cis.size() > 0) { for (ClassInfo ci : cis) { writeClass(ci); } } } public static void writeClass(ClassInfo ci) throws IOException { String className = ci.className.replace('.', File.separatorChar); String dir = outputDir + File.separatorChar + getDirName(className); mkdir(dir); // Convert name to fully qualified file name className = outputDir + File.separatorChar + className + ".class"; if (ci.className.startsWith("kilim.S_")) { // Check if we already have that file if (new File(className).exists()) return; } FileOutputStream fos = new FileOutputStream(className); fos.write(ci.bytes); fos.close(); if (verbose) { System.out.println("Wrote: " + className); } } static void mkdir(String dir) throws IOException { File f = new File(dir); if (!f.exists()) { if (!f.mkdirs()) { throw new IOException("Unable to create directory: " + dir); } } } static String getDirName(String className) { int end = className.lastIndexOf(File.separatorChar); return (end == -1) ? "" : className.substring(0, end); } static void help() { System.err.println("java kilim.tools.Weaver opts -d (class/directory/jar)+"); System.err.println(" where opts are -q : quiet"); System.err.println(" -x : exclude all classes matching regex"); System.err.println(" -f : weave even if up to date"); System.err.println(" -c : don't add targets to classpath"); System.exit(1); } public static ArrayList parseArgs(String[] args) throws IOException { if (args.length == 0) help(); ArrayList ret = new ArrayList(args.length); String regex = null; for (int i = 0; i < args.length; i++) { String arg = args[i]; if (arg.equals("-d")) { outputDir = args[++i]; } else if (arg.equals("-q")) { verbose = false; } else if (arg.equals("-f")) { force = true; } else if (arg.equals("-c")) { proxy = false; } else if (arg.equals("-h")) { help(); } else if (arg.equals("-x")) { regex = args[++i]; excludePattern = Pattern.compile(regex); } else { ret.add(arg); } } if (outputDir == null) { System.err.println("Specify output directory with -d option"); System.exit(1); } return ret; } /** * Analyzes the list of supplied classes and inserts Kilim-related bytecode if necessary. If a * supplied class is dependent upon another class X, it is the caller's responsibility to ensure * that X is either in the classpath, or loaded by the context classloader, or has been seen in * an earlier invocation of weave(). * * Since weave() remembers method signatures from earlier invocations, the woven classes do not * have to be classloaded to help future invocations of weave. * * If two classes A and B are not in the classpath, and are mutually recursive, they can be woven * only if supplied in the same input list. * * This method is thread safe. * * @param classes A list of (className, byte[]) pairs. The first part is a fully qualified class * name, and the second part is the bytecode for the class. * * @return A list of (className, byte[]) pairs. Some of the classes may or may not have been * modified, and new ones may be added. * * @throws KilimException */ public List weave(List classes) throws KilimException, IOException { // save the detector attached to this thread, if any. It will be restored // later. ArrayList ret = new ArrayList(classes.size()); try { // First cache all the method signatures from the supplied classes to allow // the weaver to lookup method signatures from mutually recursive classes. for (ClassInfo cl : classes) { context.detector.mirrors.mirror(cl.bytes); } // Now weave them individually for (ClassInfo cl : classes) { InputStream is = new ByteArrayInputStream(cl.bytes); ClassWeaver cw = new ClassWeaver(context,is); cw.weave(); ret.addAll(cw.getClassInfos()); // one class file can result in multiple classes } return ret; } finally { } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy