/* * eXist Open Source Native XML Database * Copyright (C) 2014 The eXist Project * http://exist-db.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id$ */ package org.exist.collections.triggers; import org.exist.util.sax.event.SAXEvent; import org.exist.util.sax.event.contenthandler.*; import org.exist.util.sax.event.lexicalhandler.*; import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.xml.sax.SAXException; import java.util.ArrayDeque; import java.util.Deque; /** * DeferrableFilteringTrigger decorates a FilteringTrigger with the * ability to capture and defer the processing of events. * * By default all events are dispatched to 'super' unless * we are deferring events and then they are queued. * When events are realised from the deferred queue * they will then be dispatched to 'super', you may override * either {@see applyDeferredEvents()} or one or more of the * _deferred methods to change this behaviour. * * @author Adam Retter <adam.retter@googlemail.com> */ public abstract class DeferrableFilteringTrigger extends FilteringTrigger { private boolean defer = false; protected Deque<SAXEvent> deferred = new ArrayDeque<>(); public boolean isDeferring() { return defer; } /** * Controls the deferral of FilteringTrigger * event processing. * * If we are deferring events and this function is called * with 'false' then deferred events will be applied * by calling {@see applyDeferredEvents()} * * @param defer Should we defer the processing of events? */ public void defer(final boolean defer) throws SAXException { if(this.defer && defer == false) { applyDeferredEvents(); } this.defer = defer; } @Override public void setDocumentLocator(final Locator locator) { if(defer) { deferred.add(new SetDocumentLocator(locator)); } else { super.setDocumentLocator(locator); } } @Override public void startDocument() throws SAXException { if(defer) { deferred.add(StartDocument.INSTANCE); } else { super.startDocument(); } } @Override public void endDocument() throws SAXException { if(defer) { deferred.add(EndDocument.INSTANCE); } else { super.endDocument(); } } @Override public void startPrefixMapping(final String prefix, final String uri) throws SAXException { if(defer) { deferred.add(new StartPrefixMapping(prefix, uri)); } else { super.startPrefixMapping(prefix, uri); } } @Override public void endPrefixMapping(final String prefix) throws SAXException { if(defer) { deferred.add(new EndPrefixMapping(prefix)); } else { super.endPrefixMapping(prefix); } } @Override public void startElement(final String namespaceURI, final String localName, final String qname, final Attributes attributes) throws SAXException { if(defer) { deferred.add(new StartElement(namespaceURI, localName, qname, attributes)); } else { super.startElement(namespaceURI, localName, qname, attributes); } } @Override public void endElement(final String namespaceURI, final String localName, final String qname) throws SAXException { if(defer) { deferred.add(new EndElement(namespaceURI, localName, qname)); } else { super.endElement(namespaceURI, localName, qname); } } @Override public void characters(final char[] ch, final int start, final int length) throws SAXException { if(defer) { deferred.add(new Characters(ch, start, length)); } else { super.characters(ch, start, length); } } @Override public void ignorableWhitespace(final char[] ch, final int start, final int length) throws SAXException { if(defer) { deferred.add(new IgnorableWhitespace(ch, start, length)); } else { super.ignorableWhitespace(ch, start, length); } } @Override public void processingInstruction(final String target, final String data) throws SAXException { if(defer) { deferred.add(new ProcessingInstruction(target, data)); } else { super.processingInstruction(target, data); } } @Override public void skippedEntity(final String name) throws SAXException { if(defer) { deferred.add(new SkippedEntity(name)); } else { super.skippedEntity(name); } } @Override public void startDTD(final String name, final String publicId, final String systemId) throws SAXException { if(defer) { deferred.add(new StartDTD(name, publicId, systemId)); } else { super.startDTD(name, publicId, systemId); } } @Override public void endDTD() throws SAXException { if(defer) { deferred.add(EndDTD.INSTANCE); } else { super.endDTD(); } } @Override public void startEntity(final String name) throws SAXException { if(defer) { deferred.add(new StartEntity(name)); } else { super.startEntity(name); } } @Override public void endEntity(final String name) throws SAXException { if(defer) { deferred.add(new EndEntity(name)); } else { super.endEntity(name); } } @Override public void startCDATA() throws SAXException { if(defer) { deferred.add(StartCDATA.INSTANCE); } else { super.startCDATA(); } } @Override public void endCDATA() throws SAXException { if(defer) { deferred.add(EndCDATA.INSTANCE); } else { super.endCDATA(); } } @Override public void comment(final char[] ch, final int start, final int length) throws SAXException { if(defer) { deferred.add(new Comment(ch, start, length)); } else { super.comment(ch, start, length); } } /** * Applies any deferred events * by dispatching to the appropriate _deferred method */ protected void applyDeferredEvents() throws SAXException { SAXEvent event = null; while((event = deferred.poll()) != null) { if(event instanceof SetDocumentLocator) { final SetDocumentLocator setDocumentLocator = (SetDocumentLocator)event; setDocumentLocator_deferred(setDocumentLocator.locator); } else if(event instanceof StartDocument) { startDocument_deferred(); } else if(event instanceof EndDocument) { endDocument_deferred(); } else if(event instanceof StartPrefixMapping) { final StartPrefixMapping startPrefixMapping = (StartPrefixMapping) event; startPrefixMapping_deferred(startPrefixMapping.prefix, startPrefixMapping.uri); } else if(event instanceof EndPrefixMapping) { final EndPrefixMapping endPrefixMapping = (EndPrefixMapping) event; endPrefixMapping_deferred(endPrefixMapping.prefix); } else if(event instanceof StartElement) { final StartElement startElement = (StartElement) event; startElement_deferred(startElement.namespaceURI, startElement.localName, startElement.qname, startElement.attributes); } else if(event instanceof EndElement) { final EndElement endElement = (EndElement) event; endElement_deferred(endElement.namespaceURI, endElement.localName, endElement.qname); } else if(event instanceof Characters) { final Characters characters = (Characters) event; characters_deferred(characters.ch, 0, characters.ch.length); } else if(event instanceof IgnorableWhitespace) { final IgnorableWhitespace ignorableWhitespace = (IgnorableWhitespace) event; ignorableWhitespace_deferred(ignorableWhitespace.ch, 0, ignorableWhitespace.ch.length); } else if(event instanceof ProcessingInstruction) { final ProcessingInstruction processingInstruction = (ProcessingInstruction) event; processingInstruction_deferred(processingInstruction.target, processingInstruction.data); } else if(event instanceof SkippedEntity) { final SkippedEntity skippedEntity = (SkippedEntity) event; skippedEntity_deferred(skippedEntity.name); } else if(event instanceof StartDTD) { final StartDTD startDTD = (StartDTD) event; startDTD_deferred(startDTD.name, startDTD.publicId, startDTD.systemId); } else if(event instanceof EndDTD) { endDTD_deferred(); } else if(event instanceof StartEntity) { final StartEntity startEntity = (StartEntity) event; startEntity_deferred(startEntity.name); } else if(event instanceof EndEntity) { final EndEntity endEntity = (EndEntity) event; endEntity_deferred(endEntity.name); } else if(event instanceof StartCDATA) { startCDATA_deferred(); } else if(event instanceof EndCDATA) { endCDATA_deferred(); } else if(event instanceof Comment) { final Comment comment = (Comment) event; comment_deferred(comment.ch, 0, comment.ch.length); } } } //<editor-fold desc="Deferred ContentHandler"> protected void setDocumentLocator_deferred(final Locator locator) { super.setDocumentLocator(locator); } protected void startDocument_deferred() throws SAXException { super.startDocument(); } protected void endDocument_deferred() throws SAXException { super.endDocument(); } protected void startPrefixMapping_deferred(final String prefix, final String uri) throws SAXException { super.startPrefixMapping(prefix, uri); } protected void endPrefixMapping_deferred(final String prefix) throws SAXException { super.endPrefixMapping(prefix); } protected void startElement_deferred(final String namespaceUri, final String localName, final String qName, final Attributes attrs) throws SAXException { super.startElement(namespaceUri, localName, qName, attrs); } protected void endElement_deferred(final String namespaceUri, final String localName, final String qName) throws SAXException { super.endElement(namespaceUri, localName, qName); } protected void characters_deferred(final char[] ch, final int start, final int length) throws SAXException { super.characters(ch, start, length); } protected void ignorableWhitespace_deferred(final char[] ch, final int start, final int length) throws SAXException { super.ignorableWhitespace(ch, start, length); } protected void processingInstruction_deferred(final String target, final String data) throws SAXException { super.processingInstruction(target, data); } protected void skippedEntity_deferred(final String name) throws SAXException { super.skippedEntity(name); } //</editor-fold> //<editor-fold desc="Deferred Lexical"> protected void startDTD_deferred(final String name, final String publicId, final String systemId) throws SAXException { super.startDTD(name, publicId, systemId); } protected void endDTD_deferred() throws SAXException { super.endDTD(); } protected void startEntity_deferred(final String name) throws SAXException { super.startEntity(name); } protected void endEntity_deferred(final String name) throws SAXException { super.endEntity(name); } protected void startCDATA_deferred() throws SAXException { super.startCDATA(); } protected void endCDATA_deferred() throws SAXException { super.endCDATA(); } protected void comment_deferred(final char[] ch, final int start, final int length) throws SAXException { super.comment(ch, start, length); } //</editor-fold> }