0001: /***
0002: * ASM XML Adapter
0003: * Copyright (c) 2004, Eugene Kuleshov
0004: * All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions
0008: * are met:
0009: * 1. Redistributions of source code must retain the above copyright
0010: * notice, this list of conditions and the following disclaimer.
0011: * 2. Redistributions in binary form must reproduce the above copyright
0012: * notice, this list of conditions and the following disclaimer in the
0013: * documentation and/or other materials provided with the distribution.
0014: * 3. Neither the name of the copyright holders nor the names of its
0015: * contributors may be used to endorse or promote products derived from
0016: * this software without specific prior written permission.
0017: *
0018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
0028: * THE POSSIBILITY OF SUCH DAMAGE.
0029: */package org.objectweb.asm.xml;
0030:
0031: import java.io.BufferedOutputStream;
0032: import java.io.ByteArrayInputStream;
0033: import java.io.ByteArrayOutputStream;
0034: import java.io.FileInputStream;
0035: import java.io.FileOutputStream;
0036: import java.io.IOException;
0037: import java.io.InputStream;
0038: import java.io.OutputStream;
0039: import java.io.OutputStreamWriter;
0040: import java.io.Writer;
0041: import java.util.zip.ZipEntry;
0042: import java.util.zip.ZipInputStream;
0043: import java.util.zip.ZipOutputStream;
0044:
0045: import javax.xml.transform.Source;
0046: import javax.xml.transform.Templates;
0047: import javax.xml.transform.TransformerConfigurationException;
0048: import javax.xml.transform.TransformerException;
0049: import javax.xml.transform.TransformerFactory;
0050: import javax.xml.transform.sax.SAXResult;
0051: import javax.xml.transform.sax.SAXSource;
0052: import javax.xml.transform.sax.SAXTransformerFactory;
0053: import javax.xml.transform.sax.TransformerHandler;
0054: import javax.xml.transform.stream.StreamSource;
0055:
0056: import org.objectweb.asm.ClassReader;
0057:
0058: import org.xml.sax.Attributes;
0059: import org.xml.sax.ContentHandler;
0060: import org.xml.sax.InputSource;
0061: import org.xml.sax.SAXException;
0062: import org.xml.sax.XMLReader;
0063: import org.xml.sax.ext.LexicalHandler;
0064: import org.xml.sax.helpers.AttributesImpl;
0065: import org.xml.sax.helpers.DefaultHandler;
0066: import org.xml.sax.helpers.XMLReaderFactory;
0067:
0068: /**
0069: * Processor is a command line tool that can be used for bytecode waving
0070: * directed by XSL transformation. <p> In order to use a concrete XSLT engine,
0071: * system property <tt>javax.xml.transform.TransformerFactory</tt> must be set
0072: * to one of the following values.
0073: *
0074: * <blockquote> <table border="1" cellspacing="0" cellpadding="3"> <tr> <td>jd.xslt</td>
0075: * <td>jd.xml.xslt.trax.TransformerFactoryImpl</td> </tr>
0076: *
0077: * <tr> <td>Saxon</td> <td>net.sf.saxon.TransformerFactoryImpl</td> </tr>
0078: *
0079: * <tr> <td>Caucho</td> <td>com.caucho.xsl.Xsl</td> </tr>
0080: *
0081: * <tr> <td>Xalan interpeter</td> <td>org.apache.xalan.processor.TransformerFactory</td>
0082: * </tr>
0083: *
0084: * <tr> <td>Xalan xsltc</td> <td>org.apache.xalan.xsltc.trax.TransformerFactoryImpl</td>
0085: * </tr> </table> </blockquote>
0086: *
0087: * @author Eugene Kuleshov
0088: */
0089: public class Processor {
0090:
0091: public static final int BYTECODE = 1;
0092:
0093: public static final int MULTI_XML = 2;
0094:
0095: public static final int SINGLE_XML = 3;
0096:
0097: private static final String SINGLE_XML_NAME = "classes.xml";
0098:
0099: private int inRepresentation;
0100:
0101: private int outRepresentation;
0102:
0103: private InputStream input = null;
0104:
0105: private OutputStream output = null;
0106:
0107: private Source xslt = null;
0108:
0109: private boolean computeMax;
0110:
0111: private int n = 0;
0112:
0113: public Processor(final int inRepresenation,
0114: final int outRepresentation, final InputStream input,
0115: final OutputStream output, final Source xslt) {
0116: this .inRepresentation = inRepresenation;
0117: this .outRepresentation = outRepresentation;
0118: this .input = input;
0119: this .output = output;
0120: this .xslt = xslt;
0121: this .computeMax = true;
0122: }
0123:
0124: public int process() throws TransformerException, IOException,
0125: SAXException {
0126: ZipInputStream zis = new ZipInputStream(input);
0127: final ZipOutputStream zos = new ZipOutputStream(output);
0128: final OutputStreamWriter osw = new OutputStreamWriter(zos);
0129:
0130: Thread.currentThread().setContextClassLoader(
0131: getClass().getClassLoader());
0132:
0133: TransformerFactory tf = TransformerFactory.newInstance();
0134: if (!tf.getFeature(SAXSource.FEATURE)
0135: || !tf.getFeature(SAXResult.FEATURE)) {
0136: return 0;
0137: }
0138:
0139: SAXTransformerFactory saxtf = (SAXTransformerFactory) tf;
0140: Templates templates = null;
0141: if (xslt != null) {
0142: templates = saxtf.newTemplates(xslt);
0143: }
0144:
0145: // configuring outHandlerFactory
0146: // ///////////////////////////////////////////////////////
0147:
0148: EntryElement entryElement = getEntryElement(zos);
0149:
0150: ContentHandler outDocHandler = null;
0151: switch (outRepresentation) {
0152: case BYTECODE:
0153: outDocHandler = new OutputSlicingHandler(
0154: new ASMContentHandlerFactory(zos, computeMax),
0155: entryElement, false);
0156: break;
0157:
0158: case MULTI_XML:
0159: outDocHandler = new OutputSlicingHandler(
0160: new SAXWriterFactory(osw, true), entryElement, true);
0161: break;
0162:
0163: case SINGLE_XML:
0164: ZipEntry outputEntry = new ZipEntry(SINGLE_XML_NAME);
0165: zos.putNextEntry(outputEntry);
0166: outDocHandler = new SAXWriter(osw, false);
0167: break;
0168:
0169: }
0170:
0171: // configuring inputDocHandlerFactory
0172: // /////////////////////////////////////////////////
0173: ContentHandler inDocHandler = null;
0174: if (templates == null) {
0175: inDocHandler = outDocHandler;
0176: } else {
0177: inDocHandler = new InputSlicingHandler("class",
0178: outDocHandler, new TransformerHandlerFactory(saxtf,
0179: templates, outDocHandler));
0180: }
0181: ContentHandlerFactory inDocHandlerFactory = new SubdocumentHandlerFactory(
0182: inDocHandler);
0183:
0184: if (inDocHandler != null && inRepresentation != SINGLE_XML) {
0185: inDocHandler.startDocument();
0186: inDocHandler.startElement("", "classes", "classes",
0187: new AttributesImpl());
0188: }
0189:
0190: int i = 0;
0191: ZipEntry ze = null;
0192: while ((ze = zis.getNextEntry()) != null) {
0193: update(ze.getName(), n++);
0194: if (isClassEntry(ze)) {
0195: processEntry(zis, ze, inDocHandlerFactory);
0196: } else {
0197: OutputStream os = entryElement.openEntry(getName(ze));
0198: copyEntry(zis, os);
0199: entryElement.closeEntry();
0200: }
0201:
0202: i++;
0203: }
0204:
0205: if (inDocHandler != null && inRepresentation != SINGLE_XML) {
0206: inDocHandler.endElement("", "classes", "classes");
0207: inDocHandler.endDocument();
0208: }
0209:
0210: if (outRepresentation == SINGLE_XML) {
0211: zos.closeEntry();
0212: }
0213: zos.flush();
0214: zos.close();
0215:
0216: return i;
0217: }
0218:
0219: private void copyEntry(final InputStream is, final OutputStream os)
0220: throws IOException {
0221: if (outRepresentation == SINGLE_XML) {
0222: return;
0223: }
0224:
0225: byte[] buff = new byte[2048];
0226: int i;
0227: while ((i = is.read(buff)) != -1) {
0228: os.write(buff, 0, i);
0229: }
0230: }
0231:
0232: private boolean isClassEntry(final ZipEntry ze) {
0233: String name = ze.getName();
0234: return inRepresentation == SINGLE_XML
0235: && name.equals(SINGLE_XML_NAME)
0236: || name.endsWith(".class")
0237: || name.endsWith(".class.xml");
0238: }
0239:
0240: private void processEntry(final ZipInputStream zis,
0241: final ZipEntry ze,
0242: final ContentHandlerFactory handlerFactory) {
0243: ContentHandler handler = handlerFactory.createContentHandler();
0244: try {
0245:
0246: // if (CODE2ASM.equals(command)) { // read bytecode and process it
0247: // // with TraceClassVisitor
0248: // ClassReader cr = new ClassReader(readEntry(zis, ze));
0249: // cr.accept(new TraceClassVisitor(null, new PrintWriter(os)),
0250: // false);
0251: // }
0252:
0253: boolean singleInputDocument = inRepresentation == SINGLE_XML;
0254: if (inRepresentation == BYTECODE) { // read bytecode and process it
0255: // with handler
0256: ClassReader cr = new ClassReader(readEntry(zis, ze));
0257: cr.accept(new SAXClassAdapter(handler,
0258: singleInputDocument), 0);
0259:
0260: } else { // read XML and process it with handler
0261: XMLReader reader = XMLReaderFactory.createXMLReader();
0262: reader.setContentHandler(handler);
0263: reader
0264: .parse(new InputSource(
0265: singleInputDocument ? (InputStream) new ProtectedInputStream(
0266: zis)
0267: : new ByteArrayInputStream(
0268: readEntry(zis, ze))));
0269:
0270: }
0271: } catch (Exception ex) {
0272: update(ze.getName(), 0);
0273: update(ex, 0);
0274: }
0275: }
0276:
0277: private EntryElement getEntryElement(final ZipOutputStream zos) {
0278: if (outRepresentation == SINGLE_XML) {
0279: return new SingleDocElement(zos);
0280: }
0281: return new ZipEntryElement(zos);
0282: }
0283:
0284: // private ContentHandlerFactory getHandlerFactory(
0285: // OutputStream os,
0286: // SAXTransformerFactory saxtf,
0287: // Templates templates)
0288: // {
0289: // ContentHandlerFactory factory = null;
0290: // if (templates == null) {
0291: // if (outputRepresentation == BYTECODE) { // factory used to write
0292: // // bytecode
0293: // factory = new ASMContentHandlerFactory(os, computeMax);
0294: // } else { // factory used to write XML
0295: // factory = new SAXWriterFactory(os, true);
0296: // }
0297: // } else {
0298: // if (outputRepresentation == BYTECODE) { // factory used to transform
0299: // // and then write bytecode
0300: // factory = new ASMTransformerHandlerFactory(saxtf,
0301: // templates,
0302: // os,
0303: // computeMax);
0304: // } else { // factory used to transformand then write XML
0305: // factory = new TransformerHandlerFactory(saxtf,
0306: // templates,
0307: // os,
0308: // outputRepresentation == SINGLE_XML);
0309: // }
0310: // }
0311: // return factory;
0312: // }
0313:
0314: private String getName(final ZipEntry ze) {
0315: String name = ze.getName();
0316: if (isClassEntry(ze)) {
0317: if (inRepresentation != BYTECODE
0318: && outRepresentation == BYTECODE) {
0319: name = name.substring(0, name.length() - 4); // .class.xml to
0320: // .class
0321: } else if (inRepresentation == BYTECODE
0322: && outRepresentation != BYTECODE) {
0323: name = name.concat(".xml"); // .class to .class.xml
0324: }
0325: // } else if( CODE2ASM.equals( command)) {
0326: // name = name.substring( 0, name.length()-6).concat( ".asm");
0327: }
0328: return name;
0329: }
0330:
0331: private byte[] readEntry(final ZipInputStream zis, final ZipEntry ze)
0332: throws IOException {
0333: long size = ze.getSize();
0334: if (size > -1) {
0335: byte[] buff = new byte[(int) size];
0336: int k = 0;
0337: int n;
0338: while ((n = zis.read(buff, k, buff.length - k)) > 0) {
0339: k += n;
0340: }
0341: return buff;
0342: }
0343:
0344: ByteArrayOutputStream bos = new ByteArrayOutputStream();
0345: byte[] buff = new byte[4096];
0346: int i;
0347: while ((i = zis.read(buff)) != -1) {
0348: bos.write(buff, 0, i);
0349: }
0350: return bos.toByteArray();
0351: }
0352:
0353: /*
0354: * (non-Javadoc)
0355: *
0356: * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
0357: */
0358: protected void update(final Object arg, final int n) {
0359: if (arg instanceof Throwable) {
0360: ((Throwable) arg).printStackTrace();
0361: } else {
0362: if (n % 100 == 0) {
0363: System.err.println(n + " " + arg);
0364: }
0365: }
0366: }
0367:
0368: public static void main(final String[] args) throws Exception {
0369: if (args.length < 2) {
0370: showUsage();
0371: return;
0372: }
0373:
0374: int inRepresentation = getRepresentation(args[0]);
0375: int outRepresentation = getRepresentation(args[1]);
0376:
0377: InputStream is = System.in;
0378: OutputStream os = new BufferedOutputStream(System.out);
0379:
0380: Source xslt = null;
0381: // boolean computeMax = true;
0382:
0383: for (int i = 2; i < args.length; i++) {
0384: if ("-in".equals(args[i])) {
0385: is = new FileInputStream(args[++i]);
0386:
0387: } else if ("-out".equals(args[i])) {
0388: os = new BufferedOutputStream(new FileOutputStream(
0389: args[++i]));
0390:
0391: } else if ("-xslt".equals(args[i])) {
0392: xslt = new StreamSource(new FileInputStream(args[++i]));
0393:
0394: // } else if( "-computemax".equals( args[ i].toLowerCase())) {
0395: // computeMax = true;
0396:
0397: } else {
0398: showUsage();
0399: return;
0400:
0401: }
0402: }
0403:
0404: if (inRepresentation == 0 || outRepresentation == 0) {
0405: showUsage();
0406: return;
0407: }
0408:
0409: Processor m = new Processor(inRepresentation,
0410: outRepresentation, is, os, xslt);
0411:
0412: long l1 = System.currentTimeMillis();
0413: int n = m.process();
0414: long l2 = System.currentTimeMillis();
0415: System.err.println(n);
0416: System.err.println("" + (l2 - l1) + "ms " + 1000f * n
0417: / (l2 - l1) + " resources/sec");
0418: }
0419:
0420: private static int getRepresentation(final String s) {
0421: if ("code".equals(s)) {
0422: return BYTECODE;
0423: } else if ("xml".equals(s)) {
0424: return MULTI_XML;
0425: } else if ("singlexml".equals(s)) {
0426: return SINGLE_XML;
0427: }
0428: return 0;
0429: }
0430:
0431: private static void showUsage() {
0432: System.err
0433: .println("Usage: Main <in format> <out format> [-in <input jar>] [-out <output jar>] [-xslt <xslt fiel>]");
0434: System.err
0435: .println(" when -in or -out is omitted sysin and sysout would be used");
0436: System.err
0437: .println(" <in format> and <out format> - code | xml | singlexml");
0438: }
0439:
0440: /**
0441: * IputStream wrapper class used to protect input streams from being closed
0442: * by some stupid XML parsers.
0443: */
0444: private static final class ProtectedInputStream extends InputStream {
0445: private final InputStream is;
0446:
0447: private ProtectedInputStream(final InputStream is) {
0448: super ();
0449: this .is = is;
0450: }
0451:
0452: public final void close() throws IOException {
0453: }
0454:
0455: public final int read() throws IOException {
0456: return is.read();
0457: }
0458:
0459: @Override
0460: public final int read(final byte[] b, final int off,
0461: final int len) throws IOException {
0462: return is.read(b, off, len);
0463: }
0464:
0465: @Override
0466: public final int available() throws IOException {
0467: return is.available();
0468: }
0469: }
0470:
0471: /**
0472: * A {@link ContentHandlerFactory ContentHandlerFactory} is used to create
0473: * {@link org.xml.sax.ContentHandler ContentHandler} instances for concrete
0474: * context.
0475: */
0476: private static interface ContentHandlerFactory {
0477:
0478: /**
0479: * Creates an instance of the content handler.
0480: *
0481: * @return content handler
0482: */
0483: ContentHandler createContentHandler();
0484:
0485: }
0486:
0487: /**
0488: * SAXWriterFactory
0489: */
0490: private static final class SAXWriterFactory implements
0491: ContentHandlerFactory {
0492: private Writer w;
0493:
0494: private boolean optimizeEmptyElements;
0495:
0496: public SAXWriterFactory(final Writer w,
0497: final boolean optimizeEmptyElements) {
0498: this .w = w;
0499: this .optimizeEmptyElements = optimizeEmptyElements;
0500: }
0501:
0502: public final ContentHandler createContentHandler() {
0503: return new SAXWriter(w, optimizeEmptyElements);
0504: }
0505:
0506: }
0507:
0508: /**
0509: * ASMContentHandlerFactory
0510: */
0511: private static final class ASMContentHandlerFactory implements
0512: ContentHandlerFactory {
0513: private OutputStream os;
0514:
0515: private boolean computeMax;
0516:
0517: public ASMContentHandlerFactory(final OutputStream os,
0518: final boolean computeMax) {
0519: this .os = os;
0520: this .computeMax = computeMax;
0521: }
0522:
0523: public final ContentHandler createContentHandler() {
0524: return new ASMContentHandler(os, computeMax);
0525: }
0526:
0527: }
0528:
0529: /**
0530: * TransformerHandlerFactory
0531: */
0532: private static final class TransformerHandlerFactory implements
0533: ContentHandlerFactory {
0534: private SAXTransformerFactory saxtf;
0535:
0536: private Templates templates;
0537:
0538: private ContentHandler outputHandler;
0539:
0540: public TransformerHandlerFactory(
0541: final SAXTransformerFactory saxtf,
0542: final Templates templates,
0543: final ContentHandler outputHandler) {
0544: this .saxtf = saxtf;
0545: this .templates = templates;
0546: this .outputHandler = outputHandler;
0547: }
0548:
0549: public final ContentHandler createContentHandler() {
0550: try {
0551: TransformerHandler handler = saxtf
0552: .newTransformerHandler(templates);
0553: handler.setResult(new SAXResult(outputHandler));
0554: return handler;
0555: } catch (TransformerConfigurationException ex) {
0556: throw new RuntimeException(ex.toString());
0557: }
0558: }
0559: }
0560:
0561: /**
0562: * SubdocumentHandlerFactory
0563: */
0564: private final static class SubdocumentHandlerFactory implements
0565: ContentHandlerFactory {
0566: private ContentHandler subdocumentHandler;
0567:
0568: public SubdocumentHandlerFactory(
0569: final ContentHandler subdocumentHandler) {
0570: this .subdocumentHandler = subdocumentHandler;
0571: }
0572:
0573: public final ContentHandler createContentHandler() {
0574: return subdocumentHandler;
0575: }
0576:
0577: }
0578:
0579: /**
0580: * A {@link org.xml.sax.ContentHandler ContentHandler} and
0581: * {@link org.xml.sax.ext.LexicalHandler LexicalHandler} that serializes XML
0582: * from SAX 2.0 events into {@link java.io.Writer Writer}.
0583: *
0584: * <i><blockquote> This implementation does not support namespaces, entity
0585: * definitions (uncluding DTD), CDATA and text elements. </blockquote></i>
0586: */
0587: private final static class SAXWriter extends DefaultHandler
0588: implements LexicalHandler {
0589: private static final char[] OFF = " "
0590: .toCharArray();
0591:
0592: private Writer w;
0593:
0594: private boolean optimizeEmptyElements;
0595:
0596: private boolean openElement = false;
0597:
0598: private int ident = 0;
0599:
0600: /**
0601: * Creates <code>SAXWriter</code>.
0602: *
0603: * @param w writer
0604: * @param optimizeEmptyElements if set to <code>true</code>, short
0605: * XML syntax will be used for empty elements
0606: */
0607: public SAXWriter(final Writer w,
0608: final boolean optimizeEmptyElements) {
0609: this .w = w;
0610: this .optimizeEmptyElements = optimizeEmptyElements;
0611: }
0612:
0613: public final void startElement(final String ns,
0614: final String localName, final String qName,
0615: final Attributes atts) throws SAXException {
0616: try {
0617: closeElement();
0618:
0619: writeIdent();
0620: w.write("<".concat(qName));
0621: if (atts != null && atts.getLength() > 0) {
0622: writeAttributes(atts);
0623: }
0624:
0625: if (!optimizeEmptyElements) {
0626: w.write(">\n");
0627: } else {
0628: openElement = true;
0629: }
0630: ident += 2;
0631:
0632: } catch (IOException ex) {
0633: throw new SAXException(ex);
0634:
0635: }
0636: }
0637:
0638: public final void endElement(final String ns,
0639: final String localName, final String qName)
0640: throws SAXException {
0641: ident -= 2;
0642: try {
0643: if (openElement) {
0644: w.write("/>\n");
0645: openElement = false;
0646: } else {
0647: writeIdent();
0648: w.write("</" + qName + ">\n");
0649: }
0650:
0651: } catch (IOException ex) {
0652: throw new SAXException(ex);
0653:
0654: }
0655: }
0656:
0657: public final void endDocument() throws SAXException {
0658: try {
0659: w.flush();
0660:
0661: } catch (IOException ex) {
0662: throw new SAXException(ex);
0663:
0664: }
0665: }
0666:
0667: public final void comment(final char[] ch, final int off,
0668: final int len) throws SAXException {
0669: try {
0670: closeElement();
0671:
0672: writeIdent();
0673: w.write("<!-- ");
0674: w.write(ch, off, len);
0675: w.write(" -->\n");
0676:
0677: } catch (IOException ex) {
0678: throw new SAXException(ex);
0679:
0680: }
0681: }
0682:
0683: public final void startDTD(final String arg0,
0684: final String arg1, final String arg2)
0685: throws SAXException {
0686: }
0687:
0688: public final void endDTD() throws SAXException {
0689: }
0690:
0691: public final void startEntity(final String arg0)
0692: throws SAXException {
0693: }
0694:
0695: public final void endEntity(final String arg0)
0696: throws SAXException {
0697: }
0698:
0699: public final void startCDATA() throws SAXException {
0700: }
0701:
0702: public final void endCDATA() throws SAXException {
0703: }
0704:
0705: private final void writeAttributes(final Attributes atts)
0706: throws IOException {
0707: StringBuffer sb = new StringBuffer();
0708: int len = atts.getLength();
0709: for (int i = 0; i < len; i++) {
0710: sb.append(" ").append(atts.getLocalName(i)).append(
0711: "=\"").append(esc(atts.getValue(i))).append(
0712: "\"");
0713: }
0714: w.write(sb.toString());
0715: }
0716:
0717: /**
0718: * Encode string with escaping.
0719: *
0720: * @param str string to encode.
0721: * @return encoded string
0722: */
0723: private final String esc(final String str) {
0724: StringBuffer sb = new StringBuffer(str.length());
0725: for (int i = 0; i < str.length(); i++) {
0726: char ch = str.charAt(i);
0727: switch (ch) {
0728: case '&':
0729: sb.append("&");
0730: break;
0731:
0732: case '<':
0733: sb.append("<");
0734: break;
0735:
0736: case '>':
0737: sb.append(">");
0738: break;
0739:
0740: case '\"':
0741: sb.append(""");
0742: break;
0743:
0744: default:
0745: if (ch > 0x7f) {
0746: sb.append("&#").append(Integer.toString(ch))
0747: .append(';');
0748: } else {
0749: sb.append(ch);
0750: }
0751:
0752: }
0753: }
0754: return sb.toString();
0755: }
0756:
0757: private final void writeIdent() throws IOException {
0758: int n = ident;
0759: while (n > 0) {
0760: if (n > OFF.length) {
0761: w.write(OFF);
0762: n -= OFF.length;
0763: } else {
0764: w.write(OFF, 0, n);
0765: n = 0;
0766: }
0767: }
0768: }
0769:
0770: private final void closeElement() throws IOException {
0771: if (openElement) {
0772: w.write(">\n");
0773: }
0774: openElement = false;
0775: }
0776:
0777: }
0778:
0779: /**
0780: * A {@link org.xml.sax.ContentHandler ContentHandler} that splits XML
0781: * documents into smaller chunks. Each chunk is processed by the nested
0782: * {@link org.xml.sax.ContentHandler ContentHandler} obtained from
0783: * {@link java.net.ContentHandlerFactory ContentHandlerFactory}. This is
0784: * useful for running XSLT engine against large XML document that will
0785: * hardly fit into the memory all together. <p> TODO use complete path for
0786: * subdocumentRoot
0787: */
0788: private final static class InputSlicingHandler extends
0789: DefaultHandler {
0790: private String subdocumentRoot;
0791:
0792: private ContentHandler rootHandler;
0793:
0794: private ContentHandlerFactory subdocumentHandlerFactory;
0795:
0796: private boolean subdocument = false;
0797:
0798: private ContentHandler subdocumentHandler;
0799:
0800: /**
0801: * Constructs a new {@link InputSlicingHandler SubdocumentHandler}
0802: * object.
0803: *
0804: * @param subdocumentRoot name/path to the root element of the
0805: * subdocument
0806: * @param rootHandler content handler for the entire document
0807: * (subdocument envelope).
0808: * @param subdocumentHandlerFactory a
0809: * {@link ContentHandlerFactory ContentHandlerFactory} used to
0810: * create {@link ContentHandler ContentHandler} instances for
0811: * subdocuments.
0812: */
0813: public InputSlicingHandler(final String subdocumentRoot,
0814: final ContentHandler rootHandler,
0815: final ContentHandlerFactory subdocumentHandlerFactory) {
0816: this .subdocumentRoot = subdocumentRoot;
0817: this .rootHandler = rootHandler;
0818: this .subdocumentHandlerFactory = subdocumentHandlerFactory;
0819: }
0820:
0821: public final void startElement(final String namespaceURI,
0822: final String localName, final String qName,
0823: final Attributes list) throws SAXException {
0824: if (subdocument) {
0825: subdocumentHandler.startElement(namespaceURI,
0826: localName, qName, list);
0827: } else if (localName.equals(subdocumentRoot)) {
0828: subdocumentHandler = subdocumentHandlerFactory
0829: .createContentHandler();
0830: subdocumentHandler.startDocument();
0831: subdocumentHandler.startElement(namespaceURI,
0832: localName, qName, list);
0833: subdocument = true;
0834: } else if (rootHandler != null) {
0835: rootHandler.startElement(namespaceURI, localName,
0836: qName, list);
0837: }
0838: }
0839:
0840: public final void endElement(final String namespaceURI,
0841: final String localName, final String qName)
0842: throws SAXException {
0843: if (subdocument) {
0844: subdocumentHandler.endElement(namespaceURI, localName,
0845: qName);
0846: if (localName.equals(subdocumentRoot)) {
0847: subdocumentHandler.endDocument();
0848: subdocument = false;
0849: }
0850: } else if (rootHandler != null) {
0851: rootHandler.endElement(namespaceURI, localName, qName);
0852: }
0853: }
0854:
0855: public final void startDocument() throws SAXException {
0856: if (rootHandler != null) {
0857: rootHandler.startDocument();
0858: }
0859: }
0860:
0861: public final void endDocument() throws SAXException {
0862: if (rootHandler != null) {
0863: rootHandler.endDocument();
0864:
0865: }
0866: }
0867:
0868: public final void characters(final char[] buff,
0869: final int offset, final int size) throws SAXException {
0870: if (subdocument) {
0871: subdocumentHandler.characters(buff, offset, size);
0872: } else if (rootHandler != null) {
0873: rootHandler.characters(buff, offset, size);
0874: }
0875: }
0876:
0877: }
0878:
0879: /**
0880: * A {@link org.xml.sax.ContentHandler ContentHandler} that splits XML
0881: * documents into smaller chunks. Each chunk is processed by the nested
0882: * {@link org.xml.sax.ContentHandler ContentHandler} obtained from
0883: * {@link java.net.ContentHandlerFactory ContentHandlerFactory}. This is
0884: * useful for running XSLT engine against large XML document that will
0885: * hardly fit into the memory all together.
0886: *
0887: * <p> TODO use complete path for subdocumentRoot
0888: */
0889: private static final class OutputSlicingHandler extends
0890: DefaultHandler {
0891: private String subdocumentRoot;
0892:
0893: private ContentHandlerFactory subdocumentHandlerFactory;
0894:
0895: private EntryElement entryElement;
0896:
0897: private boolean isXml;
0898:
0899: private boolean subdocument = false;
0900:
0901: private ContentHandler subdocumentHandler;
0902:
0903: /**
0904: * Constructs a new {@link OutputSlicingHandler SubdocumentHandler}
0905: * object.
0906: *
0907: * @param subdocumentHandlerFactory a
0908: * {@link ContentHandlerFactory ContentHandlerFactory} used to
0909: * create {@link ContentHandler ContentHandler} instances for
0910: * subdocuments.
0911: * @param entryElement TODO.
0912: * @param isXml TODO.
0913: */
0914: public OutputSlicingHandler(
0915: final ContentHandlerFactory subdocumentHandlerFactory,
0916: final EntryElement entryElement, final boolean isXml) {
0917: this .subdocumentRoot = "class";
0918: this .subdocumentHandlerFactory = subdocumentHandlerFactory;
0919: this .entryElement = entryElement;
0920: this .isXml = isXml;
0921: }
0922:
0923: public final void startElement(final String namespaceURI,
0924: final String localName, final String qName,
0925: final Attributes list) throws SAXException {
0926: if (subdocument) {
0927: subdocumentHandler.startElement(namespaceURI,
0928: localName, qName, list);
0929: } else if (localName.equals(subdocumentRoot)) {
0930: String name = list.getValue("name");
0931: if (name == null || name.length() == 0) {
0932: throw new SAXException(
0933: "Class element without name attribute.");
0934: }
0935: try {
0936: entryElement.openEntry(isXml ? name
0937: .concat(".class.xml") : name
0938: .concat(".class"));
0939: } catch (IOException ex) {
0940: throw new SAXException(ex.toString(), ex);
0941: }
0942: subdocumentHandler = subdocumentHandlerFactory
0943: .createContentHandler();
0944: subdocumentHandler.startDocument();
0945: subdocumentHandler.startElement(namespaceURI,
0946: localName, qName, list);
0947: subdocument = true;
0948: }
0949: }
0950:
0951: public final void endElement(final String namespaceURI,
0952: final String localName, final String qName)
0953: throws SAXException {
0954: if (subdocument) {
0955: subdocumentHandler.endElement(namespaceURI, localName,
0956: qName);
0957: if (localName.equals(subdocumentRoot)) {
0958: subdocumentHandler.endDocument();
0959: subdocument = false;
0960: try {
0961: entryElement.closeEntry();
0962: } catch (IOException ex) {
0963: throw new SAXException(ex.toString(), ex);
0964: }
0965: }
0966: }
0967: }
0968:
0969: public final void startDocument() throws SAXException {
0970: }
0971:
0972: public final void endDocument() throws SAXException {
0973: }
0974:
0975: public final void characters(final char[] buff,
0976: final int offset, final int size) throws SAXException {
0977: if (subdocument) {
0978: subdocumentHandler.characters(buff, offset, size);
0979: }
0980: }
0981:
0982: }
0983:
0984: private static interface EntryElement {
0985:
0986: OutputStream openEntry(String name) throws IOException;
0987:
0988: void closeEntry() throws IOException;
0989:
0990: }
0991:
0992: private static final class SingleDocElement implements EntryElement {
0993: private OutputStream os;
0994:
0995: public SingleDocElement(final OutputStream os) {
0996: this .os = os;
0997: }
0998:
0999: public OutputStream openEntry(final String name)
1000: throws IOException {
1001: return os;
1002: }
1003:
1004: public void closeEntry() throws IOException {
1005: os.flush();
1006: }
1007:
1008: }
1009:
1010: private static final class ZipEntryElement implements EntryElement {
1011: private ZipOutputStream zos;
1012:
1013: public ZipEntryElement(final ZipOutputStream zos) {
1014: this .zos = zos;
1015: }
1016:
1017: public OutputStream openEntry(final String name)
1018: throws IOException {
1019: ZipEntry entry = new ZipEntry(name);
1020: zos.putNextEntry(entry);
1021: return zos;
1022: }
1023:
1024: public void closeEntry() throws IOException {
1025: zos.flush();
1026: zos.closeEntry();
1027: }
1028:
1029: }
1030:
1031: }
|