/*** * ASM XML Adapter * Copyright (c) 2004-2011, Eugene Kuleshov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ package org.objectweb.asm.xml; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import javax.xml.transform.Source; import javax.xml.transform.Templates; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamSource; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.ext.LexicalHandler; import org.xml.sax.helpers.AttributesImpl; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; /** * Processor is a command line tool that can be used for bytecode waving * directed by XSL transformation. *
* In order to use a concrete XSLT engine, system property * javax.xml.transform.TransformerFactory must be set to one of the * following values. * *
** * @author Eugene Kuleshov */ public class Processor { public static final int BYTECODE = 1; public static final int MULTI_XML = 2; public static final int SINGLE_XML = 3; private static final String SINGLE_XML_NAME = "classes.xml"; private final int inRepresentation; private final int outRepresentation; private final InputStream input; private final OutputStream output; private final Source xslt; private int n = 0; public Processor(final int inRepresenation, final int outRepresentation, final InputStream input, final OutputStream output, final Source xslt) { this.inRepresentation = inRepresenation; this.outRepresentation = outRepresentation; this.input = input; this.output = output; this.xslt = xslt; } public int process() throws TransformerException, IOException, SAXException { ZipInputStream zis = new ZipInputStream(input); final ZipOutputStream zos = new ZipOutputStream(output); final OutputStreamWriter osw = new OutputStreamWriter(zos); Thread.currentThread().setContextClassLoader( getClass().getClassLoader()); TransformerFactory tf = TransformerFactory.newInstance(); if (!tf.getFeature(SAXSource.FEATURE) || !tf.getFeature(SAXResult.FEATURE)) { return 0; } SAXTransformerFactory saxtf = (SAXTransformerFactory) tf; Templates templates = null; if (xslt != null) { templates = saxtf.newTemplates(xslt); } // configuring outHandlerFactory // /////////////////////////////////////////////////////// EntryElement entryElement = getEntryElement(zos); ContentHandler outDocHandler = null; switch (outRepresentation) { case BYTECODE: outDocHandler = new OutputSlicingHandler( new ASMContentHandlerFactory(zos), entryElement, false); break; case MULTI_XML: outDocHandler = new OutputSlicingHandler(new SAXWriterFactory(osw, true), entryElement, true); break; case SINGLE_XML: ZipEntry outputEntry = new ZipEntry(SINGLE_XML_NAME); zos.putNextEntry(outputEntry); outDocHandler = new SAXWriter(osw, false); break; } // configuring inputDocHandlerFactory // ///////////////////////////////////////////////// ContentHandler inDocHandler; if (templates == null) { inDocHandler = outDocHandler; } else { inDocHandler = new InputSlicingHandler("class", outDocHandler, new TransformerHandlerFactory(saxtf, templates, outDocHandler)); } ContentHandlerFactory inDocHandlerFactory = new SubdocumentHandlerFactory( inDocHandler); if (inDocHandler != null && inRepresentation != SINGLE_XML) { inDocHandler.startDocument(); inDocHandler.startElement("", "classes", "classes", new AttributesImpl()); } int i = 0; ZipEntry ze; while ((ze = zis.getNextEntry()) != null) { update(ze.getName(), n++); if (isClassEntry(ze)) { processEntry(zis, ze, inDocHandlerFactory); } else { OutputStream os = entryElement.openEntry(getName(ze)); copyEntry(zis, os); entryElement.closeEntry(); } i++; } if (inDocHandler != null && inRepresentation != SINGLE_XML) { inDocHandler.endElement("", "classes", "classes"); inDocHandler.endDocument(); } if (outRepresentation == SINGLE_XML) { zos.closeEntry(); } zos.flush(); zos.close(); return i; } private void copyEntry(final InputStream is, final OutputStream os) throws IOException { if (outRepresentation == SINGLE_XML) { return; } byte[] buff = new byte[2048]; int i; while ((i = is.read(buff)) != -1) { os.write(buff, 0, i); } } private boolean isClassEntry(final ZipEntry ze) { String name = ze.getName(); return inRepresentation == SINGLE_XML && name.equals(SINGLE_XML_NAME) || name.endsWith(".class") || name.endsWith(".class.xml"); } private void processEntry(final ZipInputStream zis, final ZipEntry ze, final ContentHandlerFactory handlerFactory) { ContentHandler handler = handlerFactory.createContentHandler(); try { // if (CODE2ASM.equals(command)) { // read bytecode and process it // // with TraceClassVisitor // ClassReader cr = new ClassReader(readEntry(zis, ze)); // cr.accept(new TraceClassVisitor(null, new PrintWriter(os)), // false); // } boolean singleInputDocument = inRepresentation == SINGLE_XML; if (inRepresentation == BYTECODE) { // read bytecode and process it // with handler ClassReader cr = new ClassReader(readEntry(zis, ze)); cr.accept(new SAXClassAdapter(handler, singleInputDocument), 0); } else { // read XML and process it with handler XMLReader reader = XMLReaderFactory.createXMLReader(); reader.setContentHandler(handler); reader.parse(new InputSource( singleInputDocument ? (InputStream) new ProtectedInputStream( zis) : new ByteArrayInputStream(readEntry(zis, ze)))); } } catch (Exception ex) { update(ze.getName(), 0); update(ex, 0); } } private EntryElement getEntryElement(final ZipOutputStream zos) { if (outRepresentation == SINGLE_XML) { return new SingleDocElement(zos); } return new ZipEntryElement(zos); } // private ContentHandlerFactory getHandlerFactory( // OutputStream os, // SAXTransformerFactory saxtf, // Templates templates) // { // ContentHandlerFactory factory = null; // if (templates == null) { // if (outputRepresentation == BYTECODE) { // factory used to write // // bytecode // factory = new ASMContentHandlerFactory(os, computeMax); // } else { // factory used to write XML // factory = new SAXWriterFactory(os, true); // } // } else { // if (outputRepresentation == BYTECODE) { // factory used to transform // // and then write bytecode // factory = new ASMTransformerHandlerFactory(saxtf, // templates, // os, // computeMax); // } else { // factory used to transformand then write XML // factory = new TransformerHandlerFactory(saxtf, // templates, // os, // outputRepresentation == SINGLE_XML); // } // } // return factory; // } private String getName(final ZipEntry ze) { String name = ze.getName(); if (isClassEntry(ze)) { if (inRepresentation != BYTECODE && outRepresentation == BYTECODE) { name = name.substring(0, name.length() - 4); // .class.xml to // .class } else if (inRepresentation == BYTECODE && outRepresentation != BYTECODE) { name += ".xml"; // .class to .class.xml } // } else if( CODE2ASM.equals( command)) { // name = name.substring( 0, name.length()-6).concat( ".asm"); } return name; } private static byte[] readEntry(final InputStream zis, final ZipEntry ze) throws IOException { long size = ze.getSize(); if (size > -1) { byte[] buff = new byte[(int) size]; int k = 0; int n; while ((n = zis.read(buff, k, buff.length - k)) > 0) { k += n; } return buff; } ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] buff = new byte[4096]; int i; while ((i = zis.read(buff)) != -1) { bos.write(buff, 0, i); } return bos.toByteArray(); } /* * (non-Javadoc) * * @see java.util.Observer#update(java.util.Observable, java.lang.Object) */ protected void update(final Object arg, final int n) { if (arg instanceof Throwable) { ((Throwable) arg).printStackTrace(); } else { if (n % 100 == 0) { System.err.println(n + " " + arg); } } } public static void main(final String[] args) throws Exception { if (args.length < 2) { showUsage(); return; } int inRepresentation = getRepresentation(args[0]); int outRepresentation = getRepresentation(args[1]); InputStream is = System.in; OutputStream os = new BufferedOutputStream(System.out); Source xslt = null; // boolean computeMax = true; for (int i = 2; i < args.length; i++) { if ("-in".equals(args[i])) { is = new FileInputStream(args[++i]); } else if ("-out".equals(args[i])) { os = new BufferedOutputStream(new FileOutputStream(args[++i])); } else if ("-xslt".equals(args[i])) { xslt = new StreamSource(new FileInputStream(args[++i])); // } else if( "-computemax".equals( args[ i].toLowerCase())) { // computeMax = true; } else { showUsage(); return; } } if (inRepresentation == 0 || outRepresentation == 0) { showUsage(); return; } Processor m = new Processor(inRepresentation, outRepresentation, is, os, xslt); long l1 = System.currentTimeMillis(); int n = m.process(); long l2 = System.currentTimeMillis(); System.err.println(n); System.err.println((l2 - l1) + "ms " + 1000f * n / (l2 - l1) + " resources/sec"); } private static int getRepresentation(final String s) { if ("code".equals(s)) { return BYTECODE; } else if ("xml".equals(s)) { return MULTI_XML; } else if ("singlexml".equals(s)) { return SINGLE_XML; } return 0; } private static void showUsage() { System.err .println("Usage: Main*
** * *jd.xslt *jd.xml.xslt.trax.TransformerFactoryImpl ** * *Saxon *net.sf.saxon.TransformerFactoryImpl ** * *Caucho *com.caucho.xsl.Xsl ** * *Xalan interpeter *org.apache.xalan.processor.TransformerFactory ** *Xalan xsltc *org.apache.xalan.xsltc.trax.TransformerFactoryImpl *