1 30 31 package oracle.toplink.libraries.asm.xml; 32 33 import java.io.BufferedOutputStream ; 34 import java.io.ByteArrayInputStream ; 35 import java.io.ByteArrayOutputStream ; 36 import java.io.FileInputStream ; 37 import java.io.FileOutputStream ; 38 import java.io.IOException ; 39 import java.io.InputStream ; 40 import java.io.OutputStream ; 41 import java.io.OutputStreamWriter ; 42 import java.io.Writer ; 43 import java.util.zip.ZipEntry ; 44 import java.util.zip.ZipInputStream ; 45 import java.util.zip.ZipOutputStream ; 46 47 import javax.xml.transform.Source ; 48 import javax.xml.transform.Templates ; 49 import javax.xml.transform.TransformerConfigurationException ; 50 import javax.xml.transform.TransformerException ; 51 import javax.xml.transform.TransformerFactory ; 52 import javax.xml.transform.sax.SAXResult ; 53 import javax.xml.transform.sax.SAXSource ; 54 import javax.xml.transform.sax.SAXTransformerFactory ; 55 import javax.xml.transform.sax.TransformerHandler ; 56 import javax.xml.transform.stream.StreamSource ; 57 58 import oracle.toplink.libraries.asm.ClassReader; 59 60 import org.xml.sax.Attributes ; 61 import org.xml.sax.ContentHandler ; 62 import org.xml.sax.InputSource ; 63 import org.xml.sax.SAXException ; 64 import org.xml.sax.XMLReader ; 65 import org.xml.sax.ext.LexicalHandler ; 66 import org.xml.sax.helpers.AttributesImpl ; 67 import org.xml.sax.helpers.DefaultHandler ; 68 import org.xml.sax.helpers.XMLReaderFactory ; 69 70 71 110 public class Processor { 111 public static final int BYTECODE = 1; 112 public static final int MULTI_XML = 2; 113 public static final int SINGLE_XML = 3; 114 115 private static final String SINGLE_XML_NAME = "classes.xml"; 116 117 private int inRepresentation; 118 private int outRepresentation; 119 120 private InputStream input = null; 121 private OutputStream output = null; 122 private Source xslt = null; 123 private boolean computeMax; 124 125 private int n = 0; 126 127 128 public Processor( int inRepresenation, int outRepresentation, 129 InputStream input, OutputStream output, Source xslt) { 130 this.inRepresentation = inRepresenation; 131 this.outRepresentation = outRepresentation; 132 this.input = input; 133 this.output = output; 134 this.xslt = xslt; 135 this.computeMax = true; 136 } 137 138 public int process() throws TransformerException , IOException , SAXException { 139 ZipInputStream zis = new ZipInputStream ( input); 140 final ZipOutputStream zos = new ZipOutputStream ( output); 141 final OutputStreamWriter osw = new OutputStreamWriter ( zos); 142 143 Thread.currentThread().setContextClassLoader( getClass().getClassLoader()); 144 145 TransformerFactory tf = TransformerFactory.newInstance(); 146 if( !tf.getFeature( SAXSource.FEATURE) || !tf.getFeature( SAXResult.FEATURE)) return 0; 147 148 SAXTransformerFactory saxtf = ( SAXTransformerFactory ) tf; 149 Templates templates = null; 150 if( xslt!=null) { 151 templates = saxtf.newTemplates( xslt); 152 } 153 154 155 157 EntryElement entryElement = getEntryElement( zos); 158 159 ContentHandler outDocHandler = null; 160 switch( outRepresentation) { 161 case BYTECODE: 162 outDocHandler = new OutputSlicingHandler( new ASMContentHandlerFactory( zos, computeMax), entryElement, false); 163 break; 164 165 case MULTI_XML: 166 outDocHandler = new OutputSlicingHandler( new SAXWriterFactory( osw, true), entryElement, true); 167 break; 168 169 case SINGLE_XML: 170 ZipEntry outputEntry = new ZipEntry ( SINGLE_XML_NAME); 171 zos.putNextEntry( outputEntry); 172 outDocHandler = new SAXWriter( osw, false); 173 break; 174 175 } 176 177 ContentHandler inDocHandler = null; 179 if( templates==null) { 180 inDocHandler = outDocHandler; 181 } else { 182 inDocHandler = new InputSlicingHandler( "class", outDocHandler, 183 new TransformerHandlerFactory( saxtf, templates, outDocHandler)); 184 } 185 ContentHandlerFactory inDocHandlerFactory = new SubdocumentHandlerFactory( inDocHandler); 186 187 if( inDocHandler!=null && inRepresentation!=SINGLE_XML) { 188 inDocHandler.startDocument(); 189 inDocHandler.startElement( "", "classes", "classes", new AttributesImpl ()); 190 } 191 192 int n = 0; 193 ZipEntry ze = null; 194 while(( ze = zis.getNextEntry())!=null) { 195 if( isClassEntry( ze)) { 196 processEntry( zis, ze, inDocHandlerFactory); 197 } else { 198 OutputStream os = entryElement.openEntry( getName( ze)); 199 copyEntry( zis, os); 200 entryElement.closeEntry(); 201 } 202 203 n++; 204 update( ze.getName()); 205 } 206 207 if( inDocHandler!=null && inRepresentation!=SINGLE_XML) { 208 inDocHandler.endElement( "", "classes", "classes"); 209 inDocHandler.endDocument(); 210 } 211 212 if( outRepresentation==SINGLE_XML) { 213 zos.closeEntry(); 214 } 215 zos.flush(); 216 zos.close(); 217 218 return n; 219 } 220 221 private void copyEntry( InputStream is, OutputStream os) throws IOException { 222 if( outRepresentation==SINGLE_XML) return; 223 224 byte[] buff = new byte[2048]; 225 int n; 226 while ((n = is.read(buff)) != -1) { 227 os.write(buff, 0, n); 228 } 229 } 230 231 private boolean isClassEntry( ZipEntry ze) { 232 String name = ze.getName(); 233 return inRepresentation==SINGLE_XML && name.equals( SINGLE_XML_NAME) || 234 name.endsWith( ".class") || name.endsWith( ".class.xml"); 235 } 236 237 private void processEntry( final ZipInputStream zis, ZipEntry ze, ContentHandlerFactory handlerFactory) { 238 ContentHandler handler = handlerFactory.createContentHandler(); 239 try { 240 246 boolean singleInputDocument = inRepresentation==SINGLE_XML; 247 if( inRepresentation==BYTECODE) { ClassReader cr = new ClassReader( readEntry( zis, ze)); 249 cr.accept( new SAXClassAdapter( handler, singleInputDocument), false); 250 251 } else { XMLReader reader = XMLReaderFactory.createXMLReader(); 253 reader.setContentHandler( handler); 254 reader.parse( new InputSource ( singleInputDocument ? 255 ( InputStream ) new ProtectedInputStream( zis) : new ByteArrayInputStream ( readEntry( zis, ze)))); 256 257 } 258 } catch( Exception ex) { 259 update( ze.getName()); 260 update( ex); 261 } 262 } 263 264 private EntryElement getEntryElement( ZipOutputStream zos) { 265 if( outRepresentation==SINGLE_XML) { 266 return new SingleDocElement( zos); 267 } else { 268 return new ZipEntryElement( zos); 269 } 270 } 271 272 296 297 private String getName( ZipEntry ze) { 298 String name = ze.getName(); 299 if( isClassEntry( ze)) { 300 if( inRepresentation!=BYTECODE && outRepresentation==BYTECODE) { 301 name = name.substring( 0, name.length()-4); } else if( inRepresentation==BYTECODE && outRepresentation!=BYTECODE) { 303 name = name.concat( ".xml"); } 305 } 308 return name; 309 } 310 311 private byte[] readEntry(ZipInputStream zis, ZipEntry ze) throws IOException { 312 long size = ze.getSize(); 313 if (size > -1) { 314 byte[] buff = new byte[(int) size]; 315 zis.read(buff); 320 return buff; 321 } else { 322 ByteArrayOutputStream bos = new ByteArrayOutputStream (); 323 byte[] buff = new byte[4096]; 324 int n; 325 while(( n = zis.read(buff)) != -1) { 326 bos.write(buff, 0, n); 327 } 328 return bos.toByteArray(); 329 } 330 } 331 332 333 337 public void update( Object arg) { 338 if( arg instanceof Throwable ) { 339 (( Throwable ) arg).printStackTrace(); 340 } else { 341 if(( n % 100)==0) { 342 System.err.println( n+" "+arg); 343 } 344 } 345 n++; 346 } 347 348 public static void main( String [] args) throws Exception { 349 if( args.length<2) { 350 showUsage(); 351 return; 352 } 353 354 int inRepresentation = getRepresentation( args[ 0]); 355 int outRepresentation = getRepresentation( args[ 1]); 356 357 InputStream is = null; 358 OutputStream os = null; 359 360 Source xslt = null; 361 363 for( int i = 2; i<args.length; i++) { 364 if( "-in".equals( args[ i])) { 365 is = new FileInputStream ( args[ ++i]); 366 367 } else if( "-out".equals( args[ i])) { 368 os = new BufferedOutputStream ( new FileOutputStream ( args[ ++i])); 369 370 } else if( "-xslt".equals( args[ i])) { 371 xslt = new StreamSource ( new FileInputStream ( args[ ++i])); 372 373 376 } else { 377 showUsage(); 378 return; 379 380 } 381 } 382 383 if( is==null || os==null || inRepresentation==0 || outRepresentation==0) { 384 showUsage(); 385 return; 386 } 387 388 Processor m = new Processor( inRepresentation, outRepresentation, is, os, xslt); 389 390 long l1 = System.currentTimeMillis(); 391 int n = m.process(); 392 long l2 = System.currentTimeMillis(); 393 System.err.println( n); 394 System.err.println( ""+( l2-l1)+"ms "+(1000f*n/( l2-l1))+" files/sec"); 395 } 396 397 private static int getRepresentation( String s) { 398 if( "code".equals( s)) { 399 return BYTECODE; 400 } else if( "xml".equals( s)) { 401 return MULTI_XML; 402 } else if( "singlexml".equals( s)) { 403 return SINGLE_XML; 404 } 405 return 0; 406 } 407 408 private static void showUsage() { 409 System.err.println( "Usage: Main <in format> <out format> -in <input jar> -out <output jar> [-xslt <xslt fiel>]"); 410 System.err.println( " <in format> and <out format> - code | xml | singlexml"); 411 } 412 413 414 418 private static final class ProtectedInputStream extends InputStream { 419 private final InputStream is; 420 421 private ProtectedInputStream( InputStream is) { 422 super(); 423 this.is = is; 424 } 425 426 public final void close() throws IOException { 427 } 428 429 public final int read() throws IOException { 430 return is.read(); 431 } 432 433 public final int read( byte[] b, int off, int len) throws IOException { 434 return is.read( b, off, len); 435 } 436 437 public final int available() throws IOException { 438 return is.available(); 439 } 440 } 441 442 443 447 private static interface ContentHandlerFactory { 448 449 454 ContentHandler createContentHandler(); 455 456 } 457 458 459 462 private static final class SAXWriterFactory implements ContentHandlerFactory { 463 private Writer w; 464 private boolean optimizeEmptyElements; 465 466 public SAXWriterFactory( Writer w, boolean optimizeEmptyElements) { 467 this.w = w; 468 this.optimizeEmptyElements = optimizeEmptyElements; 469 } 470 471 public final ContentHandler createContentHandler() { 472 return new SAXWriter( w, optimizeEmptyElements); 473 } 474 475 } 476 477 478 481 private static final class ASMContentHandlerFactory implements ContentHandlerFactory { 482 private OutputStream os; 483 private boolean computeMax; 484 485 public ASMContentHandlerFactory( OutputStream os, boolean computeMax) { 486 this.os = os; 487 this.computeMax = computeMax; 488 } 489 490 public final ContentHandler createContentHandler() { 491 return new ASMContentHandler( os, computeMax); 492 } 493 494 } 495 496 497 500 private static final class TransformerHandlerFactory implements ContentHandlerFactory { 501 private SAXTransformerFactory saxtf; 502 private Templates templates; 503 private ContentHandler outputHandler; 504 505 public TransformerHandlerFactory( SAXTransformerFactory saxtf, Templates templates, ContentHandler outputHandler) { 506 this.saxtf = saxtf; 507 this.templates = templates; 508 this.outputHandler = outputHandler; 509 } 510 511 public final ContentHandler createContentHandler() { 512 try { 513 TransformerHandler handler = saxtf.newTransformerHandler( templates); 514 handler.setResult( new SAXResult ( outputHandler)); 515 return handler; 516 } catch( TransformerConfigurationException ex) { 517 throw new RuntimeException ( ex.toString()); 518 } 519 } 520 } 521 522 523 526 private final static class SubdocumentHandlerFactory implements ContentHandlerFactory { 527 private ContentHandler subdocumentHandler; 528 529 public SubdocumentHandlerFactory( ContentHandler subdocumentHandler) { 530 this.subdocumentHandler = subdocumentHandler; 531 } 532 533 public final ContentHandler createContentHandler() { 534 return subdocumentHandler; 535 } 536 537 } 538 539 540 550 private final static class SAXWriter extends DefaultHandler implements LexicalHandler { 551 private static final char[] OFF = " ".toCharArray(); 552 553 private Writer w; 554 private boolean optimizeEmptyElements; 555 556 private boolean openElement = false; 557 private int ident = 0; 558 559 560 567 public SAXWriter( Writer w, boolean optimizeEmptyElements) { 568 this.w = w; 569 this.optimizeEmptyElements = optimizeEmptyElements; 570 } 571 572 public final void startElement( String ns, String localName, String qName, Attributes atts) throws SAXException { 573 try { 574 closeElement(); 575 576 writeIdent(); 577 w.write( "<".concat( qName)); 578 if( atts!=null && atts.getLength()>0) writeAttributes( atts); 579 580 if( !optimizeEmptyElements) { 581 w.write( ">\n"); 582 } else { 583 openElement = true; 584 } 585 ident += 2; 586 587 } catch( IOException ex) { 588 throw new SAXException (ex); 589 590 } 591 } 592 593 public final void endElement( String ns, String localName, String qName) throws SAXException { 594 ident -= 2; 595 try { 596 if( openElement) { 597 w.write( "/>\n"); 598 openElement = false; 599 } else { 600 writeIdent(); 601 w.write( "</"+qName+">\n"); 602 } 603 604 } catch( IOException ex) { 605 throw new SAXException (ex); 606 607 } 608 } 609 610 public final void endDocument() throws SAXException { 611 try { 612 w.flush(); 613 614 } catch( IOException ex) { 615 throw new SAXException (ex); 616 617 } 618 } 619 620 public final void comment( char[] ch, int off, int len) throws SAXException { 621 try { 622 closeElement(); 623 624 writeIdent(); 625 w.write( "<!-- "); 626 w.write( ch, off, len); 627 w.write( " -->\n"); 628 629 } catch( IOException ex) { 630 throw new SAXException (ex); 631 632 } 633 } 634 635 public final void startDTD( String arg0, String arg1, String arg2) throws SAXException { 636 } 637 638 public final void endDTD() throws SAXException { 639 } 640 641 public final void startEntity( String arg0) throws SAXException { 642 } 643 644 public final void endEntity( String arg0) throws SAXException { 645 } 646 647 public final void startCDATA() throws SAXException { 648 } 649 650 public final void endCDATA() throws SAXException { 651 } 652 653 654 private final void writeAttributes( Attributes atts) throws IOException { 655 StringBuffer sb = new StringBuffer (); 656 int len = atts.getLength(); 657 for( int i = 0; i<len; i++) { 658 sb.append( " ").append( atts.getLocalName( i)).append( "=\"") 659 .append( esc( atts.getValue( i))).append( "\""); 660 } 661 w.write( sb.toString()); 662 } 663 664 670 private final String esc( String str) { 671 StringBuffer sb = new StringBuffer ( str.length()); 672 for( int i = 0; i < str.length(); i++) { 673 char ch = str.charAt( i); 674 switch( ch) { 675 case '&': 676 sb.append( "&"); 677 break; 678 679 case '<': 680 sb.append( "<"); 681 break; 682 683 case '>': 684 sb.append( ">"); 685 break; 686 687 case '\"': 688 sb.append( """); 689 break; 690 691 default: 692 if( ch>0x7f) { 693 sb.append( "&#").append( Integer.toString( ch)).append( ';'); 694 } else { 695 sb.append( ch); 696 } 697 698 } 699 } 700 return sb.toString(); 701 } 702 703 private final void writeIdent() throws IOException { 704 int n = ident; 705 while( n>0) { 706 if( n>OFF.length) { 707 w.write( OFF); 708 n -= OFF.length; 709 } else { 710 w.write( OFF, 0, n); 711 n = 0; 712 } 713 } 714 } 715 716 private final void closeElement() throws IOException { 717 if( openElement) { 718 w.write( ">\n"); 719 } 720 openElement = false; 721 } 722 723 } 724 725 726 736 private final static class InputSlicingHandler extends DefaultHandler { 737 private String subdocumentRoot; 738 private ContentHandler rootHandler; 739 private ContentHandlerFactory subdocumentHandlerFactory; 740 741 private boolean subdocument = false; 742 private ContentHandler subdocumentHandler; 743 744 752 public InputSlicingHandler( String subdocumentRoot, ContentHandler rootHandler, 753 ContentHandlerFactory subdocumentHandlerFactory) { 754 this.subdocumentRoot = subdocumentRoot; 755 this.rootHandler = rootHandler; 756 this.subdocumentHandlerFactory = subdocumentHandlerFactory; 757 } 758 759 public final void startElement( String namespaceURI, String localName, String qName, Attributes list) throws SAXException { 760 if( subdocument) { 761 subdocumentHandler.startElement( namespaceURI, localName, qName, list); 762 } else if( localName.equals( subdocumentRoot)) { 763 subdocumentHandler = subdocumentHandlerFactory.createContentHandler(); 764 subdocumentHandler.startDocument(); 765 subdocumentHandler.startElement( namespaceURI, localName, qName, list); 766 subdocument = true; 767 } else if( rootHandler!=null) { 768 rootHandler.startElement( namespaceURI, localName, qName, list); 769 } 770 } 771 772 public final void endElement( String namespaceURI, String localName, String qName) throws SAXException { 773 if( subdocument) { 774 subdocumentHandler.endElement( namespaceURI, localName, qName); 775 if( localName.equals( subdocumentRoot)) { 776 subdocumentHandler.endDocument(); 777 subdocument = false; 778 } 779 } else if( rootHandler!=null) { 780 rootHandler.endElement( namespaceURI, localName, qName); 781 } 782 } 783 784 public final void startDocument() throws SAXException { 785 if( rootHandler!=null) { 786 rootHandler.startDocument(); 787 } 788 } 789 790 public final void endDocument() throws SAXException { 791 if( rootHandler!=null) { 792 rootHandler.endDocument(); 793 794 } 795 } 796 797 public final void characters( char[] buff, int offset, int size) throws SAXException { 798 if( subdocument) { 799 subdocumentHandler.characters(buff, offset, size); 800 } else if( rootHandler!=null) { 801 rootHandler.characters(buff, offset, size); 802 } 803 } 804 805 } 806 807 808 818 private static final class OutputSlicingHandler extends DefaultHandler { 819 private String subdocumentRoot; 820 private ContentHandlerFactory subdocumentHandlerFactory; 821 private EntryElement entryElement; 822 private boolean isXml; 823 824 private boolean subdocument = false; 825 private ContentHandler subdocumentHandler; 826 827 835 public OutputSlicingHandler( ContentHandlerFactory subdocumentHandlerFactory, 836 EntryElement entryElement, boolean isXml) { 837 this.subdocumentRoot = "class"; 838 this.subdocumentHandlerFactory = subdocumentHandlerFactory; 839 this.entryElement = entryElement; 840 this.isXml = isXml; 841 } 842 843 public final void startElement( String namespaceURI, String localName, String qName, Attributes list) throws SAXException { 844 if( subdocument) { 845 subdocumentHandler.startElement( namespaceURI, localName, qName, list); 846 } else if( localName.equals( subdocumentRoot)) { 847 String name = list.getValue( "name"); 848 if( name==null || name.length()==0) throw new SAXException ( "Class element without name attribute."); 849 try { 850 entryElement.openEntry( isXml ? name.concat( ".class.xml") : name.concat( ".class")); 851 } catch( IOException ex) { 852 throw new SAXException ( ex.toString(), ex); 853 } 854 subdocumentHandler = subdocumentHandlerFactory.createContentHandler(); 855 subdocumentHandler.startDocument(); 856 subdocumentHandler.startElement( namespaceURI, localName, qName, list); 857 subdocument = true; 858 } 859 } 860 861 public final void endElement( String namespaceURI, String localName, String qName) throws SAXException { 862 if( subdocument) { 863 subdocumentHandler.endElement( namespaceURI, localName, qName); 864 if( localName.equals( subdocumentRoot)) { 865 subdocumentHandler.endDocument(); 866 subdocument = false; 867 try { 868 entryElement.closeEntry(); 869 } catch( IOException ex) { 870 throw new SAXException ( ex.toString(), ex); 871 } 872 } 873 } 874 } 875 876 public final void startDocument() throws SAXException { 877 } 878 879 public final void endDocument() throws SAXException { 880 } 881 882 public final void characters( char[] buff, int offset, int size) throws SAXException { 883 if( subdocument) { 884 subdocumentHandler.characters(buff, offset, size); 885 } 886 } 887 888 } 889 890 891 private static interface EntryElement { 892 893 OutputStream openEntry( String name) throws IOException ; 894 895 void closeEntry() throws IOException ; 896 897 } 898 899 900 private static final class SingleDocElement implements EntryElement { 901 private OutputStream os; 902 903 public SingleDocElement( OutputStream os) { 904 this.os = os; 905 } 906 907 public OutputStream openEntry( String name) throws IOException { 908 return os; 909 } 910 911 public void closeEntry() throws IOException { 912 os.flush(); 913 } 914 915 } 916 917 918 private static final class ZipEntryElement implements EntryElement { 919 private ZipOutputStream zos; 920 921 public ZipEntryElement( ZipOutputStream zos) { 922 this.zos = zos; 923 } 924 925 public OutputStream openEntry( String name) throws IOException { 926 ZipEntry entry = new ZipEntry ( name); 927 zos.putNextEntry( entry); 928 return zos; 929 } 930 931 public void closeEntry() throws IOException { 932 zos.flush(); 933 zos.closeEntry(); 934 } 935 936 } 937 938 } 939 940 | Popular Tags |