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.ejb3unit.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.ejb3unit.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: public final int read(final byte[] b, final int off,
0460: final int len) throws IOException {
0461: return is.read(b, off, len);
0462: }
0463:
0464: public final int available() throws IOException {
0465: return is.available();
0466: }
0467: }
0468:
0469: /**
0470: * A {@link ContentHandlerFactory ContentHandlerFactory} is used to create
0471: * {@link org.xml.sax.ContentHandler ContentHandler} instances for concrete
0472: * context.
0473: */
0474: private static interface ContentHandlerFactory {
0475:
0476: /**
0477: * Creates an instance of the content handler.
0478: *
0479: * @return content handler
0480: */
0481: ContentHandler createContentHandler();
0482:
0483: }
0484:
0485: /**
0486: * SAXWriterFactory
0487: */
0488: private static final class SAXWriterFactory implements
0489: ContentHandlerFactory {
0490: private Writer w;
0491:
0492: private boolean optimizeEmptyElements;
0493:
0494: public SAXWriterFactory(final Writer w,
0495: final boolean optimizeEmptyElements) {
0496: this .w = w;
0497: this .optimizeEmptyElements = optimizeEmptyElements;
0498: }
0499:
0500: public final ContentHandler createContentHandler() {
0501: return new SAXWriter(w, optimizeEmptyElements);
0502: }
0503:
0504: }
0505:
0506: /**
0507: * ASMContentHandlerFactory
0508: */
0509: private static final class ASMContentHandlerFactory implements
0510: ContentHandlerFactory {
0511: private OutputStream os;
0512:
0513: private boolean computeMax;
0514:
0515: public ASMContentHandlerFactory(final OutputStream os,
0516: final boolean computeMax) {
0517: this .os = os;
0518: this .computeMax = computeMax;
0519: }
0520:
0521: public final ContentHandler createContentHandler() {
0522: return new ASMContentHandler(os, computeMax);
0523: }
0524:
0525: }
0526:
0527: /**
0528: * TransformerHandlerFactory
0529: */
0530: private static final class TransformerHandlerFactory implements
0531: ContentHandlerFactory {
0532: private SAXTransformerFactory saxtf;
0533:
0534: private Templates templates;
0535:
0536: private ContentHandler outputHandler;
0537:
0538: public TransformerHandlerFactory(
0539: final SAXTransformerFactory saxtf,
0540: final Templates templates,
0541: final ContentHandler outputHandler) {
0542: this .saxtf = saxtf;
0543: this .templates = templates;
0544: this .outputHandler = outputHandler;
0545: }
0546:
0547: public final ContentHandler createContentHandler() {
0548: try {
0549: TransformerHandler handler = saxtf
0550: .newTransformerHandler(templates);
0551: handler.setResult(new SAXResult(outputHandler));
0552: return handler;
0553: } catch (TransformerConfigurationException ex) {
0554: throw new RuntimeException(ex.toString());
0555: }
0556: }
0557: }
0558:
0559: /**
0560: * SubdocumentHandlerFactory
0561: */
0562: private final static class SubdocumentHandlerFactory implements
0563: ContentHandlerFactory {
0564: private ContentHandler subdocumentHandler;
0565:
0566: public SubdocumentHandlerFactory(
0567: final ContentHandler subdocumentHandler) {
0568: this .subdocumentHandler = subdocumentHandler;
0569: }
0570:
0571: public final ContentHandler createContentHandler() {
0572: return subdocumentHandler;
0573: }
0574:
0575: }
0576:
0577: /**
0578: * A {@link org.xml.sax.ContentHandler ContentHandler} and
0579: * {@link org.xml.sax.ext.LexicalHandler LexicalHandler} that serializes XML
0580: * from SAX 2.0 events into {@link java.io.Writer Writer}.
0581: *
0582: * <i><blockquote> This implementation does not support namespaces, entity
0583: * definitions (uncluding DTD), CDATA and text elements. </blockquote></i>
0584: */
0585: private final static class SAXWriter extends DefaultHandler
0586: implements LexicalHandler {
0587: private static final char[] OFF = " "
0588: .toCharArray();
0589:
0590: private Writer w;
0591:
0592: private boolean optimizeEmptyElements;
0593:
0594: private boolean openElement = false;
0595:
0596: private int ident = 0;
0597:
0598: /**
0599: * Creates <code>SAXWriter</code>.
0600: *
0601: * @param w writer
0602: * @param optimizeEmptyElements if set to <code>true</code>, short
0603: * XML syntax will be used for empty elements
0604: */
0605: public SAXWriter(final Writer w,
0606: final boolean optimizeEmptyElements) {
0607: this .w = w;
0608: this .optimizeEmptyElements = optimizeEmptyElements;
0609: }
0610:
0611: public final void startElement(final String ns,
0612: final String localName, final String qName,
0613: final Attributes atts) throws SAXException {
0614: try {
0615: closeElement();
0616:
0617: writeIdent();
0618: w.write("<".concat(qName));
0619: if (atts != null && atts.getLength() > 0) {
0620: writeAttributes(atts);
0621: }
0622:
0623: if (!optimizeEmptyElements) {
0624: w.write(">\n");
0625: } else {
0626: openElement = true;
0627: }
0628: ident += 2;
0629:
0630: } catch (IOException ex) {
0631: throw new SAXException(ex);
0632:
0633: }
0634: }
0635:
0636: public final void endElement(final String ns,
0637: final String localName, final String qName)
0638: throws SAXException {
0639: ident -= 2;
0640: try {
0641: if (openElement) {
0642: w.write("/>\n");
0643: openElement = false;
0644: } else {
0645: writeIdent();
0646: w.write("</" + qName + ">\n");
0647: }
0648:
0649: } catch (IOException ex) {
0650: throw new SAXException(ex);
0651:
0652: }
0653: }
0654:
0655: public final void endDocument() throws SAXException {
0656: try {
0657: w.flush();
0658:
0659: } catch (IOException ex) {
0660: throw new SAXException(ex);
0661:
0662: }
0663: }
0664:
0665: public final void comment(final char[] ch, final int off,
0666: final int len) throws SAXException {
0667: try {
0668: closeElement();
0669:
0670: writeIdent();
0671: w.write("<!-- ");
0672: w.write(ch, off, len);
0673: w.write(" -->\n");
0674:
0675: } catch (IOException ex) {
0676: throw new SAXException(ex);
0677:
0678: }
0679: }
0680:
0681: public final void startDTD(final String arg0,
0682: final String arg1, final String arg2)
0683: throws SAXException {
0684: }
0685:
0686: public final void endDTD() throws SAXException {
0687: }
0688:
0689: public final void startEntity(final String arg0)
0690: throws SAXException {
0691: }
0692:
0693: public final void endEntity(final String arg0)
0694: throws SAXException {
0695: }
0696:
0697: public final void startCDATA() throws SAXException {
0698: }
0699:
0700: public final void endCDATA() throws SAXException {
0701: }
0702:
0703: private final void writeAttributes(final Attributes atts)
0704: throws IOException {
0705: StringBuffer sb = new StringBuffer();
0706: int len = atts.getLength();
0707: for (int i = 0; i < len; i++) {
0708: sb.append(' ').append(atts.getLocalName(i)).append(
0709: "=\"").append(esc(atts.getValue(i))).append(
0710: '\"');
0711: }
0712: w.write(sb.toString());
0713: }
0714:
0715: /**
0716: * Encode string with escaping.
0717: *
0718: * @param str string to encode.
0719: * @return encoded string
0720: */
0721: private final String esc(final String str) {
0722: StringBuffer sb = new StringBuffer(str.length());
0723: for (int i = 0; i < str.length(); i++) {
0724: char ch = str.charAt(i);
0725: switch (ch) {
0726: case '&':
0727: sb.append("&");
0728: break;
0729:
0730: case '<':
0731: sb.append("<");
0732: break;
0733:
0734: case '>':
0735: sb.append(">");
0736: break;
0737:
0738: case '\"':
0739: sb.append(""");
0740: break;
0741:
0742: default:
0743: if (ch > 0x7f) {
0744: sb.append("&#").append(Integer.toString(ch))
0745: .append(';');
0746: } else {
0747: sb.append(ch);
0748: }
0749:
0750: }
0751: }
0752: return sb.toString();
0753: }
0754:
0755: private final void writeIdent() throws IOException {
0756: int n = ident;
0757: while (n > 0) {
0758: if (n > OFF.length) {
0759: w.write(OFF);
0760: n -= OFF.length;
0761: } else {
0762: w.write(OFF, 0, n);
0763: n = 0;
0764: }
0765: }
0766: }
0767:
0768: private final void closeElement() throws IOException {
0769: if (openElement) {
0770: w.write(">\n");
0771: }
0772: openElement = false;
0773: }
0774:
0775: }
0776:
0777: /**
0778: * A {@link org.xml.sax.ContentHandler ContentHandler} that splits XML
0779: * documents into smaller chunks. Each chunk is processed by the nested
0780: * {@link org.xml.sax.ContentHandler ContentHandler} obtained from
0781: * {@link java.net.ContentHandlerFactory ContentHandlerFactory}. This is
0782: * useful for running XSLT engine against large XML document that will
0783: * hardly fit into the memory all together. <p> TODO use complete path for
0784: * subdocumentRoot
0785: */
0786: private final static class InputSlicingHandler extends
0787: DefaultHandler {
0788: private String subdocumentRoot;
0789:
0790: private ContentHandler rootHandler;
0791:
0792: private ContentHandlerFactory subdocumentHandlerFactory;
0793:
0794: private boolean subdocument = false;
0795:
0796: private ContentHandler subdocumentHandler;
0797:
0798: /**
0799: * Constructs a new {@link InputSlicingHandler SubdocumentHandler}
0800: * object.
0801: *
0802: * @param subdocumentRoot name/path to the root element of the
0803: * subdocument
0804: * @param rootHandler content handler for the entire document
0805: * (subdocument envelope).
0806: * @param subdocumentHandlerFactory a
0807: * {@link ContentHandlerFactory ContentHandlerFactory} used to
0808: * create {@link ContentHandler ContentHandler} instances for
0809: * subdocuments.
0810: */
0811: public InputSlicingHandler(final String subdocumentRoot,
0812: final ContentHandler rootHandler,
0813: final ContentHandlerFactory subdocumentHandlerFactory) {
0814: this .subdocumentRoot = subdocumentRoot;
0815: this .rootHandler = rootHandler;
0816: this .subdocumentHandlerFactory = subdocumentHandlerFactory;
0817: }
0818:
0819: public final void startElement(final String namespaceURI,
0820: final String localName, final String qName,
0821: final Attributes list) throws SAXException {
0822: if (subdocument) {
0823: subdocumentHandler.startElement(namespaceURI,
0824: localName, qName, list);
0825: } else if (localName.equals(subdocumentRoot)) {
0826: subdocumentHandler = subdocumentHandlerFactory
0827: .createContentHandler();
0828: subdocumentHandler.startDocument();
0829: subdocumentHandler.startElement(namespaceURI,
0830: localName, qName, list);
0831: subdocument = true;
0832: } else if (rootHandler != null) {
0833: rootHandler.startElement(namespaceURI, localName,
0834: qName, list);
0835: }
0836: }
0837:
0838: public final void endElement(final String namespaceURI,
0839: final String localName, final String qName)
0840: throws SAXException {
0841: if (subdocument) {
0842: subdocumentHandler.endElement(namespaceURI, localName,
0843: qName);
0844: if (localName.equals(subdocumentRoot)) {
0845: subdocumentHandler.endDocument();
0846: subdocument = false;
0847: }
0848: } else if (rootHandler != null) {
0849: rootHandler.endElement(namespaceURI, localName, qName);
0850: }
0851: }
0852:
0853: public final void startDocument() throws SAXException {
0854: if (rootHandler != null) {
0855: rootHandler.startDocument();
0856: }
0857: }
0858:
0859: public final void endDocument() throws SAXException {
0860: if (rootHandler != null) {
0861: rootHandler.endDocument();
0862:
0863: }
0864: }
0865:
0866: public final void characters(final char[] buff,
0867: final int offset, final int size) throws SAXException {
0868: if (subdocument) {
0869: subdocumentHandler.characters(buff, offset, size);
0870: } else if (rootHandler != null) {
0871: rootHandler.characters(buff, offset, size);
0872: }
0873: }
0874:
0875: }
0876:
0877: /**
0878: * A {@link org.xml.sax.ContentHandler ContentHandler} that splits XML
0879: * documents into smaller chunks. Each chunk is processed by the nested
0880: * {@link org.xml.sax.ContentHandler ContentHandler} obtained from
0881: * {@link java.net.ContentHandlerFactory ContentHandlerFactory}. This is
0882: * useful for running XSLT engine against large XML document that will
0883: * hardly fit into the memory all together.
0884: *
0885: * <p> TODO use complete path for subdocumentRoot
0886: */
0887: private static final class OutputSlicingHandler extends
0888: DefaultHandler {
0889: private String subdocumentRoot;
0890:
0891: private ContentHandlerFactory subdocumentHandlerFactory;
0892:
0893: private EntryElement entryElement;
0894:
0895: private boolean isXml;
0896:
0897: private boolean subdocument = false;
0898:
0899: private ContentHandler subdocumentHandler;
0900:
0901: /**
0902: * Constructs a new {@link OutputSlicingHandler SubdocumentHandler}
0903: * object.
0904: *
0905: * @param subdocumentHandlerFactory a
0906: * {@link ContentHandlerFactory ContentHandlerFactory} used to
0907: * create {@link ContentHandler ContentHandler} instances for
0908: * subdocuments.
0909: * @param entryElement TODO.
0910: * @param isXml TODO.
0911: */
0912: public OutputSlicingHandler(
0913: final ContentHandlerFactory subdocumentHandlerFactory,
0914: final EntryElement entryElement, final boolean isXml) {
0915: this .subdocumentRoot = "class";
0916: this .subdocumentHandlerFactory = subdocumentHandlerFactory;
0917: this .entryElement = entryElement;
0918: this .isXml = isXml;
0919: }
0920:
0921: public final void startElement(final String namespaceURI,
0922: final String localName, final String qName,
0923: final Attributes list) throws SAXException {
0924: if (subdocument) {
0925: subdocumentHandler.startElement(namespaceURI,
0926: localName, qName, list);
0927: } else if (localName.equals(subdocumentRoot)) {
0928: String name = list.getValue("name");
0929: if (name == null || name.length() == 0) {
0930: throw new SAXException(
0931: "Class element without name attribute.");
0932: }
0933: try {
0934: entryElement.openEntry(isXml ? name
0935: .concat(".class.xml") : name
0936: .concat(".class"));
0937: } catch (IOException ex) {
0938: throw new SAXException(ex.toString(), ex);
0939: }
0940: subdocumentHandler = subdocumentHandlerFactory
0941: .createContentHandler();
0942: subdocumentHandler.startDocument();
0943: subdocumentHandler.startElement(namespaceURI,
0944: localName, qName, list);
0945: subdocument = true;
0946: }
0947: }
0948:
0949: public final void endElement(final String namespaceURI,
0950: final String localName, final String qName)
0951: throws SAXException {
0952: if (subdocument) {
0953: subdocumentHandler.endElement(namespaceURI, localName,
0954: qName);
0955: if (localName.equals(subdocumentRoot)) {
0956: subdocumentHandler.endDocument();
0957: subdocument = false;
0958: try {
0959: entryElement.closeEntry();
0960: } catch (IOException ex) {
0961: throw new SAXException(ex.toString(), ex);
0962: }
0963: }
0964: }
0965: }
0966:
0967: public final void startDocument() throws SAXException {
0968: }
0969:
0970: public final void endDocument() throws SAXException {
0971: }
0972:
0973: public final void characters(final char[] buff,
0974: final int offset, final int size) throws SAXException {
0975: if (subdocument) {
0976: subdocumentHandler.characters(buff, offset, size);
0977: }
0978: }
0979:
0980: }
0981:
0982: private static interface EntryElement {
0983:
0984: OutputStream openEntry(String name) throws IOException;
0985:
0986: void closeEntry() throws IOException;
0987:
0988: }
0989:
0990: private static final class SingleDocElement implements EntryElement {
0991: private OutputStream os;
0992:
0993: public SingleDocElement(final OutputStream os) {
0994: this .os = os;
0995: }
0996:
0997: public OutputStream openEntry(final String name)
0998: throws IOException {
0999: return os;
1000: }
1001:
1002: public void closeEntry() throws IOException {
1003: os.flush();
1004: }
1005:
1006: }
1007:
1008: private static final class ZipEntryElement implements EntryElement {
1009: private ZipOutputStream zos;
1010:
1011: public ZipEntryElement(final ZipOutputStream zos) {
1012: this .zos = zos;
1013: }
1014:
1015: public OutputStream openEntry(final String name)
1016: throws IOException {
1017: ZipEntry entry = new ZipEntry(name);
1018: zos.putNextEntry(entry);
1019: return zos;
1020: }
1021:
1022: public void closeEntry() throws IOException {
1023: zos.flush();
1024: zos.closeEntry();
1025: }
1026:
1027: }
1028:
1029: }
|