/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.outerj.daisy.diff.helper;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.Locator;
import org.xml.sax.Attributes;
import org.xml.sax.ext.LexicalHandler;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Collections;
import java.io.Serializable;
import java.io.IOException;
import java.io.Writer;
/**
* A class that can record SAX events and replay them later.
*
* <p>
* This class was copied form the Apache Cocoon.
*/
public class SaxBuffer implements ContentHandler, LexicalHandler, Serializable {
/**
* Stores list of {@link SaxBit} objects.
*/
protected List<SaxBit> saxbits = new ArrayList<SaxBit>();
/**
* Creates empty SaxBuffer
*/
public SaxBuffer() {
}
/**
* Creates copy of another SaxBuffer
*/
public SaxBuffer(SaxBuffer saxBuffer) {
this.saxbits.addAll(saxBuffer.saxbits);
}
public void skippedEntity(String name) throws SAXException {
saxbits.add(new SkippedEntity(name));
}
public void setDocumentLocator(Locator locator) {
// don't record this event
}
public void ignorableWhitespace(char ch[], int start, int length)
throws SAXException {
saxbits.add(new IgnorableWhitespace(ch, start, length));
}
public void processingInstruction(String target, String data)
throws SAXException {
saxbits.add(new PI(target, data));
}
public void startDocument() throws SAXException {
saxbits.add(StartDocument.SINGLETON);
}
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts) throws SAXException {
saxbits.add(new StartElement(namespaceURI, localName, qName, atts));
}
public void endPrefixMapping(String prefix) throws SAXException {
saxbits.add(new EndPrefixMapping(prefix));
}
public void characters(char ch[], int start, int length)
throws SAXException {
saxbits.add(new Characters(ch, start, length));
}
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
saxbits.add(new EndElement(namespaceURI, localName, qName));
}
public void endDocument() throws SAXException {
saxbits.add(EndDocument.SINGLETON);
}
public void startPrefixMapping(String prefix, String uri)
throws SAXException {
saxbits.add(new StartPrefixMapping(prefix, uri));
}
public void endCDATA() throws SAXException {
saxbits.add(EndCDATA.SINGLETON);
}
public void comment(char ch[], int start, int length) throws SAXException {
saxbits.add(new Comment(ch, start, length));
}
public void startEntity(String name) throws SAXException {
saxbits.add(new StartEntity(name));
}
public void endDTD() throws SAXException {
saxbits.add(EndDTD.SINGLETON);
}
public void startDTD(String name, String publicId, String systemId)
throws SAXException {
saxbits.add(new StartDTD(name, publicId, systemId));
}
public void startCDATA() throws SAXException {
saxbits.add(StartCDATA.SINGLETON);
}
public void endEntity(String name) throws SAXException {
saxbits.add(new EndEntity(name));
}
/**
* Adds a SaxBit to the bits list
*/
protected final void addBit(SaxBit bit) {
saxbits.add(bit);
}
/**
* Iterates through the bits list
*/
protected final Iterator bits() {
return saxbits.iterator();
}
public boolean isEmpty() {
return saxbits.isEmpty();
}
public List<SaxBit> getBits() {
return Collections.unmodifiableList(saxbits);
}
public void toSAX(ContentHandler contentHandler) throws SAXException {
for (SaxBit saxbit : saxbits) {
saxbit.send(contentHandler);
}
}
/*
* NOTE: Used in i18n XML bundle implementation
*/
@Override
public String toString() {
StringBuilder value = new StringBuilder();
for (SaxBit saxbit : saxbits) {
if (saxbit instanceof Characters) {
((Characters) saxbit).toString(value);
}
}
return value.toString();
}
public void recycle() {
saxbits.clear();
}
public void dump(Writer writer) throws IOException {
for (SaxBit saxbit : saxbits) {
saxbit.dump(writer);
}
writer.flush();
}
/**
* SaxBit is a representation of the SAX event. Every SaxBit is immutable
* object.
*/
public interface SaxBit {
public void send(ContentHandler contentHandler) throws SAXException;
public void dump(Writer writer) throws IOException;
}
public static final class StartDocument implements SaxBit, Serializable {
public static final StartDocument SINGLETON = new StartDocument();
public void send(ContentHandler contentHandler) throws SAXException {
contentHandler.startDocument();
}
public void dump(Writer writer) throws IOException {
writer.write("[StartDocument]\n");
}
}
public static final class EndDocument implements SaxBit, Serializable {
public static final EndDocument SINGLETON = new EndDocument();
public void send(ContentHandler contentHandler) throws SAXException {
contentHandler.endDocument();
}
public void dump(Writer writer) throws IOException {
writer.write("[EndDocument]\n");
}
}
public static final class PI implements SaxBit, Serializable {
public final String target;
public final String data;
public PI(String target, String data) {
this.target = target;
this.data = data;
}
public void send(ContentHandler contentHandler) throws SAXException {
contentHandler.processingInstruction(target, data);
}
public void dump(Writer writer) throws IOException {
writer.write("[ProcessingInstruction] target=" + target + ",data="
+ data + "\n");
}
}
public static final class StartDTD implements SaxBit, Serializable {
public final String name;
public final String publicId;
public final String systemId;
public StartDTD(String name, String publicId, String systemId) {
this.name = name;
this.publicId = publicId;
this.systemId = systemId;
}
public void send(ContentHandler contentHandler) throws SAXException {
if (contentHandler instanceof LexicalHandler)
((LexicalHandler) contentHandler).startDTD(name, publicId,
systemId);
}
public void dump(Writer writer) throws IOException {
writer.write("[StartDTD] name=" + name + ",publicId=" + publicId
+ ",systemId=" + systemId + "\n");
}
}
public static final class EndDTD implements SaxBit, Serializable {
public static final EndDTD SINGLETON = new EndDTD();
public void send(ContentHandler contentHandler) throws SAXException {
if (contentHandler instanceof LexicalHandler)
((LexicalHandler) contentHandler).endDTD();
}
public void dump(Writer writer) throws IOException {
writer.write("[EndDTD]\n");
}
}
public static final class StartEntity implements SaxBit, Serializable {
public final String name;
public StartEntity(String name) {
this.name = name;
}
public void send(ContentHandler contentHandler) throws SAXException {
if (contentHandler instanceof LexicalHandler)
((LexicalHandler) contentHandler).startEntity(name);
}
public void dump(Writer writer) throws IOException {
writer.write("[StartEntity] name=" + name + "\n");
}
}
public static final class EndEntity implements SaxBit, Serializable {
public final String name;
public EndEntity(String name) {
this.name = name;
}
public void send(ContentHandler contentHandler) throws SAXException {
if (contentHandler instanceof LexicalHandler)
((LexicalHandler) contentHandler).endEntity(name);
}
public void dump(Writer writer) throws IOException {
writer.write("[EndEntity] name=" + name + "\n");
}
}
public static final class SkippedEntity implements SaxBit, Serializable {
public final String name;
public SkippedEntity(String name) {
this.name = name;
}
public void send(ContentHandler contentHandler) throws SAXException {
contentHandler.skippedEntity(name);
}
public void dump(Writer writer) throws IOException {
writer.write("[SkippedEntity] name=" + name + "\n");
}
}
public static final class StartPrefixMapping implements SaxBit,
Serializable {
public final String prefix;
public final String uri;
public StartPrefixMapping(String prefix, String uri) {
this.prefix = prefix;
this.uri = uri;
}
public void send(ContentHandler contentHandler) throws SAXException {
contentHandler.startPrefixMapping(prefix, uri);
}
public void dump(Writer writer) throws IOException {
writer.write("[StartPrefixMapping] prefix=" + prefix + ",uri="
+ uri + "\n");
}
}
public static final class EndPrefixMapping implements SaxBit, Serializable {
public final String prefix;
public EndPrefixMapping(String prefix) {
this.prefix = prefix;
}
public void send(ContentHandler contentHandler) throws SAXException {
contentHandler.endPrefixMapping(prefix);
}
public void dump(Writer writer) throws IOException {
writer.write("[EndPrefixMapping] prefix=" + prefix + "\n");
}
}
public static final class StartElement implements SaxBit, Serializable {
public final String namespaceURI;
public final String localName;
public final String qName;
public final Attributes attrs;
public StartElement(String namespaceURI, String localName,
String qName, Attributes attrs) {
this.namespaceURI = namespaceURI;
this.localName = localName;
this.qName = qName;
this.attrs = new org.xml.sax.helpers.AttributesImpl(attrs);
}
public void send(ContentHandler contentHandler) throws SAXException {
contentHandler.startElement(namespaceURI, localName, qName, attrs);
}
public void dump(Writer writer) throws IOException {
writer.write("[StartElement] namespaceURI=" + namespaceURI
+ ",localName=" + localName + ",qName=" + qName + "\n");
for (int i = 0; i < attrs.getLength(); i++) {
writer.write(" [Attribute] namespaceURI="
+ attrs.getURI(i) + ",localName="
+ attrs.getLocalName(i) + ",qName=" + attrs.getQName(i)
+ ",type=" + attrs.getType(i) + ",value="
+ attrs.getValue(i) + "\n");
}
}
}
public static final class EndElement implements SaxBit, Serializable {
public final String namespaceURI;
public final String localName;
public final String qName;
public EndElement(String namespaceURI, String localName, String qName) {
this.namespaceURI = namespaceURI;
this.localName = localName;
this.qName = qName;
}
public void send(ContentHandler contentHandler) throws SAXException {
contentHandler.endElement(namespaceURI, localName, qName);
}
public void dump(Writer writer) throws IOException {
writer.write("[EndElement] namespaceURI=" + namespaceURI
+ ",localName=" + localName + ",qName=" + qName + "\n");
}
}
public static final class Characters implements SaxBit, Serializable {
public final char[] ch;
public Characters(char[] ch, int start, int length) {
// make a copy so that we don't hold references to a potentially
// large array we don't control
this.ch = new char[length];
System.arraycopy(ch, start, this.ch, 0, length);
}
public void send(ContentHandler contentHandler) throws SAXException {
contentHandler.characters(ch, 0, ch.length);
}
public void toString(StringBuilder value) {
value.append(ch);
}
public void dump(Writer writer) throws IOException {
writer.write("[Characters] ch=" + new String(ch) + "\n");
}
}
public static final class Comment implements SaxBit, Serializable {
public final char[] ch;
public Comment(char[] ch, int start, int length) {
// make a copy so that we don't hold references to a potentially
// large array we don't control
this.ch = new char[length];
System.arraycopy(ch, start, this.ch, 0, length);
}
public void send(ContentHandler contentHandler) throws SAXException {
if (contentHandler instanceof LexicalHandler)
((LexicalHandler) contentHandler).comment(ch, 0, ch.length);
}
public void dump(Writer writer) throws IOException {
writer.write("[Comment] ch=" + new String(ch) + "\n");
}
}
public static final class StartCDATA implements SaxBit, Serializable {
public static final StartCDATA SINGLETON = new StartCDATA();
public void send(ContentHandler contentHandler) throws SAXException {
if (contentHandler instanceof LexicalHandler)
((LexicalHandler) contentHandler).startCDATA();
}
public void dump(Writer writer) throws IOException {
writer.write("[StartCDATA]\n");
}
}
public static final class EndCDATA implements SaxBit, Serializable {
public static final EndCDATA SINGLETON = new EndCDATA();
public void send(ContentHandler contentHandler) throws SAXException {
if (contentHandler instanceof LexicalHandler)
((LexicalHandler) contentHandler).endCDATA();
}
public void dump(Writer writer) throws IOException {
writer.write("[EndCDATA]\n");
}
}
public static final class IgnorableWhitespace implements SaxBit,
Serializable {
public final char[] ch;
public IgnorableWhitespace(char[] ch, int start, int length) {
// make a copy so that we don't hold references to a potentially
// large array we don't control
this.ch = new char[length];
System.arraycopy(ch, start, this.ch, 0, length);
}
public void send(ContentHandler contentHandler) throws SAXException {
contentHandler.ignorableWhitespace(ch, 0, ch.length);
}
public void dump(Writer writer) throws IOException {
writer.write("IgnorableWhitespace] ch=" + new String(ch) + "\n");
}
}
}