Clover coverage report - dom4j - 1.6.1
Coverage timestamp: ma mei 16 2005 14:23:01 GMT+01:00
file stats: LOC: 603   Methods: 29
NCLOC: 383   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
SAXEventRecorder.java 0% 0% 0% 0%
coverage
 1    /*
 2    * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
 3    *
 4    * This software is open source.
 5    * See the bottom of this file for the licence.
 6    */
 7   
 8    package org.dom4j.io;
 9   
 10    import java.io.Externalizable;
 11    import java.io.IOException;
 12    import java.io.ObjectInput;
 13    import java.io.ObjectOutput;
 14    import java.util.ArrayList;
 15    import java.util.HashMap;
 16    import java.util.Iterator;
 17    import java.util.List;
 18    import java.util.Map;
 19   
 20    import org.dom4j.Namespace;
 21    import org.dom4j.QName;
 22    import org.xml.sax.Attributes;
 23    import org.xml.sax.ContentHandler;
 24    import org.xml.sax.DTDHandler;
 25    import org.xml.sax.SAXException;
 26    import org.xml.sax.ext.DeclHandler;
 27    import org.xml.sax.ext.LexicalHandler;
 28    import org.xml.sax.helpers.AttributesImpl;
 29    import org.xml.sax.helpers.DefaultHandler;
 30   
 31    /**
 32    * <p>
 33    * Records SAX events such that they may be "replayed" at a later time. Provides
 34    * an alternative serialization approach when externalizing a DOM4J document.
 35    * Rather than serializing a document as text and re-parsing, the sax events may
 36    * be serialized instead.
 37    * </p>
 38    * Example usage:
 39    *
 40    * <pre>
 41    *
 42    *
 43    *
 44    * SAXEventRecorder recorder = new SAXEventRecorder();
 45    * SAXWriter saxWriter = new SAXWriter(recorder, recorder);
 46    * saxWriter.write(document);
 47    * out.writeObject(recorder);
 48    * ...
 49    * SAXEventRecorder recorder = (SAXEventRecorder)in.readObject();
 50    * SAXContentHandler saxContentHandler = new SAXContentHandler();
 51    * recorder.replay(saxContentHandler);
 52    * Document document = saxContentHandler.getDocument();
 53    *
 54    *
 55    *
 56    * </pre>
 57    *
 58    * @author Todd Wolff (Bluestem Software)
 59    */
 60    public class SAXEventRecorder extends DefaultHandler implements LexicalHandler,
 61    DeclHandler, DTDHandler, Externalizable {
 62    public static final long serialVersionUID = 1;
 63   
 64    private static final byte STRING = 0;
 65   
 66    private static final byte OBJECT = 1;
 67   
 68    private static final byte NULL = 2;
 69   
 70    private List events = new ArrayList();
 71   
 72    private Map prefixMappings = new HashMap();
 73   
 74    private static final String XMLNS = "xmlns";
 75   
 76    private static final String EMPTY_STRING = "";
 77   
 78  0 public SAXEventRecorder() {
 79    }
 80   
 81  0 public void replay(ContentHandler handler) throws SAXException {
 82  0 SAXEvent saxEvent;
 83  0 Iterator itr = events.iterator();
 84   
 85  0 while (itr.hasNext()) {
 86  0 saxEvent = (SAXEvent) itr.next();
 87   
 88  0 switch (saxEvent.event) {
 89    // replay to ContentHandler
 90  0 case SAXEvent.PROCESSING_INSTRUCTION:
 91  0 handler.processingInstruction((String) saxEvent.getParm(0),
 92    (String) saxEvent.getParm(1));
 93   
 94  0 break;
 95   
 96  0 case SAXEvent.START_PREFIX_MAPPING:
 97  0 handler.startPrefixMapping((String) saxEvent.getParm(0),
 98    (String) saxEvent.getParm(1));
 99   
 100  0 break;
 101   
 102  0 case SAXEvent.END_PREFIX_MAPPING:
 103  0 handler.endPrefixMapping((String) saxEvent.getParm(0));
 104   
 105  0 break;
 106   
 107  0 case SAXEvent.START_DOCUMENT:
 108  0 handler.startDocument();
 109   
 110  0 break;
 111   
 112  0 case SAXEvent.END_DOCUMENT:
 113  0 handler.endDocument();
 114   
 115  0 break;
 116   
 117  0 case SAXEvent.START_ELEMENT:
 118   
 119  0 AttributesImpl attributes = new AttributesImpl();
 120  0 List attParmList = (List) saxEvent.getParm(3);
 121   
 122  0 if (attParmList != null) {
 123  0 Iterator attsItr = attParmList.iterator();
 124   
 125  0 while (attsItr.hasNext()) {
 126  0 String[] attParms = (String[]) attsItr.next();
 127  0 attributes.addAttribute(attParms[0], attParms[1],
 128    attParms[2], attParms[3], attParms[4]);
 129    }
 130    }
 131   
 132  0 handler.startElement((String) saxEvent.getParm(0),
 133    (String) saxEvent.getParm(1), (String) saxEvent
 134    .getParm(2), attributes);
 135   
 136  0 break;
 137   
 138  0 case SAXEvent.END_ELEMENT:
 139  0 handler.endElement((String) saxEvent.getParm(0),
 140    (String) saxEvent.getParm(1), (String) saxEvent
 141    .getParm(2));
 142   
 143  0 break;
 144   
 145  0 case SAXEvent.CHARACTERS:
 146   
 147  0 char[] chars = (char[]) saxEvent.getParm(0);
 148  0 int start = ((Integer) saxEvent.getParm(1)).intValue();
 149  0 int end = ((Integer) saxEvent.getParm(2)).intValue();
 150  0 handler.characters(chars, start, end);
 151   
 152  0 break;
 153   
 154    // replay to LexicalHandler
 155  0 case SAXEvent.START_DTD:
 156  0 ((LexicalHandler) handler).startDTD((String) saxEvent
 157    .getParm(0), (String) saxEvent.getParm(1),
 158    (String) saxEvent.getParm(2));
 159   
 160  0 break;
 161   
 162  0 case SAXEvent.END_DTD:
 163  0 ((LexicalHandler) handler).endDTD();
 164   
 165  0 break;
 166   
 167  0 case SAXEvent.START_ENTITY:
 168  0 ((LexicalHandler) handler).startEntity((String) saxEvent
 169    .getParm(0));
 170   
 171  0 break;
 172   
 173  0 case SAXEvent.END_ENTITY:
 174  0 ((LexicalHandler) handler).endEntity((String) saxEvent
 175    .getParm(0));
 176   
 177  0 break;
 178   
 179  0 case SAXEvent.START_CDATA:
 180  0 ((LexicalHandler) handler).startCDATA();
 181   
 182  0 break;
 183   
 184  0 case SAXEvent.END_CDATA:
 185  0 ((LexicalHandler) handler).endCDATA();
 186   
 187  0 break;
 188   
 189  0 case SAXEvent.COMMENT:
 190   
 191  0 char[] cchars = (char[]) saxEvent.getParm(0);
 192  0 int cstart = ((Integer) saxEvent.getParm(1)).intValue();
 193  0 int cend = ((Integer) saxEvent.getParm(2)).intValue();
 194  0 ((LexicalHandler) handler).comment(cchars, cstart, cend);
 195   
 196  0 break;
 197   
 198    // replay to DeclHandler
 199  0 case SAXEvent.ELEMENT_DECL:
 200  0 ((DeclHandler) handler).elementDecl((String) saxEvent
 201    .getParm(0), (String) saxEvent.getParm(1));
 202   
 203  0 break;
 204   
 205  0 case SAXEvent.ATTRIBUTE_DECL:
 206  0 ((DeclHandler) handler).attributeDecl((String) saxEvent
 207    .getParm(0), (String) saxEvent.getParm(1),
 208    (String) saxEvent.getParm(2), (String) saxEvent
 209    .getParm(3), (String) saxEvent.getParm(4));
 210   
 211  0 break;
 212   
 213  0 case SAXEvent.INTERNAL_ENTITY_DECL:
 214  0 ((DeclHandler) handler).internalEntityDecl(
 215    (String) saxEvent.getParm(0), (String) saxEvent
 216    .getParm(1));
 217   
 218  0 break;
 219   
 220  0 case SAXEvent.EXTERNAL_ENTITY_DECL:
 221  0 ((DeclHandler) handler).externalEntityDecl(
 222    (String) saxEvent.getParm(0), (String) saxEvent
 223    .getParm(1), (String) saxEvent.getParm(2));
 224   
 225  0 break;
 226   
 227  0 default:
 228  0 throw new SAXException("Unrecognized event: "
 229    + saxEvent.event);
 230    }
 231    }
 232    }
 233   
 234    // ContentHandler interface
 235    // -------------------------------------------------------------------------
 236  0 public void processingInstruction(String target, String data)
 237    throws SAXException {
 238  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.PROCESSING_INSTRUCTION);
 239  0 saxEvent.addParm(target);
 240  0 saxEvent.addParm(data);
 241  0 events.add(saxEvent);
 242    }
 243   
 244  0 public void startPrefixMapping(String prefix, String uri)
 245    throws SAXException {
 246  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.START_PREFIX_MAPPING);
 247  0 saxEvent.addParm(prefix);
 248  0 saxEvent.addParm(uri);
 249  0 events.add(saxEvent);
 250    }
 251   
 252  0 public void endPrefixMapping(String prefix) throws SAXException {
 253  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.END_PREFIX_MAPPING);
 254  0 saxEvent.addParm(prefix);
 255  0 events.add(saxEvent);
 256    }
 257   
 258  0 public void startDocument() throws SAXException {
 259  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.START_DOCUMENT);
 260  0 events.add(saxEvent);
 261    }
 262   
 263  0 public void endDocument() throws SAXException {
 264  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.END_DOCUMENT);
 265  0 events.add(saxEvent);
 266    }
 267   
 268  0 public void startElement(String namespaceURI, String localName,
 269    String qualifiedName, Attributes attributes) throws SAXException {
 270  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.START_ELEMENT);
 271  0 saxEvent.addParm(namespaceURI);
 272  0 saxEvent.addParm(localName);
 273  0 saxEvent.addParm(qualifiedName);
 274   
 275  0 QName qName = null;
 276  0 if (namespaceURI != null) {
 277  0 qName = new QName(localName, Namespace.get(namespaceURI));
 278    } else {
 279  0 qName = new QName(localName);
 280    }
 281   
 282  0 if ((attributes != null) && (attributes.getLength() > 0)) {
 283  0 List attParmList = new ArrayList(attributes.getLength());
 284  0 String[] attParms = null;
 285   
 286  0 for (int i = 0; i < attributes.getLength(); i++) {
 287   
 288  0 String attLocalName = attributes.getLocalName(i);
 289   
 290  0 if (attLocalName.startsWith(XMLNS)) {
 291   
 292    // if SAXWriter is writing a DOMDocument, namespace
 293    // decls are treated as attributes. record a start
 294    // prefix mapping event
 295  0 String prefix = null;
 296  0 if (attLocalName.length() > 5) {
 297  0 prefix = attLocalName.substring(6);
 298    } else {
 299  0 prefix = EMPTY_STRING;
 300    }
 301   
 302  0 SAXEvent prefixEvent = new SAXEvent(
 303    SAXEvent.START_PREFIX_MAPPING);
 304  0 prefixEvent.addParm(prefix);
 305  0 prefixEvent.addParm(attributes.getValue(i));
 306  0 events.add(prefixEvent);
 307   
 308    // 'register' the prefix so that we can generate
 309    // an end prefix mapping event within endElement
 310  0 List prefixes = (List) prefixMappings.get(qName);
 311  0 if (prefixes == null) {
 312  0 prefixes = new ArrayList();
 313  0 prefixMappings.put(qName, prefixes);
 314    }
 315  0 prefixes.add(prefix);
 316   
 317    } else {
 318   
 319  0 attParms = new String[5];
 320  0 attParms[0] = attributes.getURI(i);
 321  0 attParms[1] = attLocalName;
 322  0 attParms[2] = attributes.getQName(i);
 323  0 attParms[3] = attributes.getType(i);
 324  0 attParms[4] = attributes.getValue(i);
 325  0 attParmList.add(attParms);
 326   
 327    }
 328   
 329    }
 330   
 331  0 saxEvent.addParm(attParmList);
 332    }
 333   
 334  0 events.add(saxEvent);
 335    }
 336   
 337  0 public void endElement(String namespaceURI, String localName, String qName)
 338    throws SAXException {
 339   
 340  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.END_ELEMENT);
 341  0 saxEvent.addParm(namespaceURI);
 342  0 saxEvent.addParm(localName);
 343  0 saxEvent.addParm(qName);
 344  0 events.add(saxEvent);
 345   
 346    // check to see if a we issued a start prefix mapping event
 347    // for DOMDocument namespace decls
 348   
 349  0 QName elementName = null;
 350  0 if (namespaceURI != null) {
 351  0 elementName = new QName(localName, Namespace.get(namespaceURI));
 352    } else {
 353  0 elementName = new QName(localName);
 354    }
 355   
 356  0 List prefixes = (List) prefixMappings.get(elementName);
 357  0 if (prefixes != null) {
 358  0 Iterator itr = prefixes.iterator();
 359  0 while (itr.hasNext()) {
 360  0 SAXEvent prefixEvent =
 361    new SAXEvent(SAXEvent.END_PREFIX_MAPPING);
 362  0 prefixEvent.addParm(itr.next());
 363  0 events.add(prefixEvent);
 364    }
 365    }
 366   
 367    }
 368   
 369  0 public void characters(char[] ch, int start, int end) throws SAXException {
 370  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.CHARACTERS);
 371  0 saxEvent.addParm(ch);
 372  0 saxEvent.addParm(new Integer(start));
 373  0 saxEvent.addParm(new Integer(end));
 374  0 events.add(saxEvent);
 375    }
 376   
 377    // LexicalHandler interface
 378    // -------------------------------------------------------------------------
 379  0 public void startDTD(String name, String publicId, String systemId)
 380    throws SAXException {
 381  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.START_DTD);
 382  0 saxEvent.addParm(name);
 383  0 saxEvent.addParm(publicId);
 384  0 saxEvent.addParm(systemId);
 385  0 events.add(saxEvent);
 386    }
 387   
 388  0 public void endDTD() throws SAXException {
 389  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.END_DTD);
 390  0 events.add(saxEvent);
 391    }
 392   
 393  0 public void startEntity(String name) throws SAXException {
 394  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.START_ENTITY);
 395  0 saxEvent.addParm(name);
 396  0 events.add(saxEvent);
 397    }
 398   
 399  0 public void endEntity(String name) throws SAXException {
 400  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.END_ENTITY);
 401  0 saxEvent.addParm(name);
 402  0 events.add(saxEvent);
 403    }
 404   
 405  0 public void startCDATA() throws SAXException {
 406  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.START_CDATA);
 407  0 events.add(saxEvent);
 408    }
 409   
 410  0 public void endCDATA() throws SAXException {
 411  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.END_CDATA);
 412  0 events.add(saxEvent);
 413    }
 414   
 415  0 public void comment(char[] ch, int start, int end) throws SAXException {
 416  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.COMMENT);
 417  0 saxEvent.addParm(ch);
 418  0 saxEvent.addParm(new Integer(start));
 419  0 saxEvent.addParm(new Integer(end));
 420  0 events.add(saxEvent);
 421    }
 422   
 423    // DeclHandler interface
 424    // -------------------------------------------------------------------------
 425  0 public void elementDecl(String name, String model) throws SAXException {
 426  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.ELEMENT_DECL);
 427  0 saxEvent.addParm(name);
 428  0 saxEvent.addParm(model);
 429  0 events.add(saxEvent);
 430    }
 431   
 432  0 public void attributeDecl(String eName, String aName, String type,
 433    String valueDefault, String value) throws SAXException {
 434  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.ATTRIBUTE_DECL);
 435  0 saxEvent.addParm(eName);
 436  0 saxEvent.addParm(aName);
 437  0 saxEvent.addParm(type);
 438  0 saxEvent.addParm(valueDefault);
 439  0 saxEvent.addParm(value);
 440  0 events.add(saxEvent);
 441    }
 442   
 443  0 public void internalEntityDecl(String name, String value)
 444    throws SAXException {
 445  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.INTERNAL_ENTITY_DECL);
 446  0 saxEvent.addParm(name);
 447  0 saxEvent.addParm(value);
 448  0 events.add(saxEvent);
 449    }
 450   
 451  0 public void externalEntityDecl(String name, String publicId, String sysId)
 452    throws SAXException {
 453  0 SAXEvent saxEvent = new SAXEvent(SAXEvent.EXTERNAL_ENTITY_DECL);
 454  0 saxEvent.addParm(name);
 455  0 saxEvent.addParm(publicId);
 456  0 saxEvent.addParm(sysId);
 457  0 events.add(saxEvent);
 458    }
 459   
 460  0 public void writeExternal(ObjectOutput out) throws IOException {
 461  0 if (events == null) {
 462  0 out.writeByte(NULL);
 463    } else {
 464  0 out.writeByte(OBJECT);
 465  0 out.writeObject(events);
 466    }
 467    }
 468   
 469  0 public void readExternal(ObjectInput in) throws ClassNotFoundException,
 470    IOException {
 471  0 if (in.readByte() != NULL) {
 472  0 events = (List) in.readObject();
 473    }
 474    }
 475   
 476    // SAXEvent inner class
 477    // -------------------------------------------------------------------------
 478    static class SAXEvent implements Externalizable {
 479    public static final long serialVersionUID = 1;
 480   
 481    static final byte PROCESSING_INSTRUCTION = 1;
 482   
 483    static final byte START_PREFIX_MAPPING = 2;
 484   
 485    static final byte END_PREFIX_MAPPING = 3;
 486   
 487    static final byte START_DOCUMENT = 4;
 488   
 489    static final byte END_DOCUMENT = 5;
 490   
 491    static final byte START_ELEMENT = 6;
 492   
 493    static final byte END_ELEMENT = 7;
 494   
 495    static final byte CHARACTERS = 8;
 496   
 497    static final byte START_DTD = 9;
 498   
 499    static final byte END_DTD = 10;
 500   
 501    static final byte START_ENTITY = 11;
 502   
 503    static final byte END_ENTITY = 12;
 504   
 505    static final byte START_CDATA = 13;
 506   
 507    static final byte END_CDATA = 14;
 508   
 509    static final byte COMMENT = 15;
 510   
 511    static final byte ELEMENT_DECL = 16;
 512   
 513    static final byte ATTRIBUTE_DECL = 17;
 514   
 515    static final byte INTERNAL_ENTITY_DECL = 18;
 516   
 517    static final byte EXTERNAL_ENTITY_DECL = 19;
 518   
 519    protected byte event;
 520   
 521    protected List parms;
 522   
 523  0 public SAXEvent() {
 524    }
 525   
 526  0 SAXEvent(byte event) {
 527  0 this.event = event;
 528    }
 529   
 530  0 void addParm(Object parm) {
 531  0 if (parms == null) {
 532  0 parms = new ArrayList(3);
 533    }
 534   
 535  0 parms.add(parm);
 536    }
 537   
 538  0 Object getParm(int index) {
 539  0 if ((parms != null) && (index < parms.size())) {
 540  0 return parms.get(index);
 541    } else {
 542  0 return null;
 543    }
 544    }
 545   
 546  0 public void writeExternal(ObjectOutput out) throws IOException {
 547  0 out.writeByte(event);
 548   
 549  0 if (parms == null) {
 550  0 out.writeByte(NULL);
 551    } else {
 552  0 out.writeByte(OBJECT);
 553  0 out.writeObject(parms);
 554    }
 555    }
 556   
 557  0 public void readExternal(ObjectInput in) throws ClassNotFoundException,
 558    IOException {
 559  0 event = in.readByte();
 560   
 561  0 if (in.readByte() != NULL) {
 562  0 parms = (List) in.readObject();
 563    }
 564    }
 565    }
 566    }
 567   
 568    /*
 569    * Redistribution and use of this software and associated documentation
 570    * ("Software"), with or without modification, are permitted provided that the
 571    * following conditions are met:
 572    *
 573    * 1. Redistributions of source code must retain copyright statements and
 574    * notices. Redistributions must also contain a copy of this document.
 575    *
 576    * 2. Redistributions in binary form must reproduce the above copyright notice,
 577    * this list of conditions and the following disclaimer in the documentation
 578    * and/or other materials provided with the distribution.
 579    *
 580    * 3. The name "DOM4J" must not be used to endorse or promote products derived
 581    * from this Software without prior written permission of MetaStuff, Ltd. For
 582    * written permission, please contact dom4j-info@metastuff.com.
 583    *
 584    * 4. Products derived from this Software may not be called "DOM4J" nor may
 585    * "DOM4J" appear in their names without prior written permission of MetaStuff,
 586    * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
 587    *
 588    * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
 589    *
 590    * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
 591    * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 592    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 593    * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
 594    * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 595    * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 596    * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 597    * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 598    * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 599    * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 600    * POSSIBILITY OF SUCH DAMAGE.
 601    *
 602    * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
 603    */