/* QuiXProc: efficient evaluation of XProc Pipelines. Copyright (C) 2011-2015 Innovimax All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package innovimax.quixproc.datamodel.event; import java.util.HashMap; import java.util.Map; import innovimax.quixproc.datamodel.IQuiXToken; import innovimax.quixproc.datamodel.QuiXCharStream; import innovimax.quixproc.datamodel.QuiXQName; import innovimax.quixproc.datamodel.QuiXToken; public abstract class AQuiXEvent implements IQuiXEvent, IQuiXToken { // TODO : store namespace context // TODO : store type information for PSVI // to enable CACHING for specific kind of type private static final boolean SEQUENCE_CACHING_ENABLED = false; private static final boolean DOCUMENT_CACHING_ENABLED = false; private static final boolean ELEMENT_CACHING_ENABLED = false; private static final boolean NAME_CACHING_ENABLED = false; private static long createCount = 0; private static long createCallCount = 0; static long createDocCount = 0; static long createAttrCount = 0; protected final QuiXToken type; /* constructors */ AQuiXEvent(QuiXToken type) { this.type = type; createCount++; } public abstract static class AXMLQuiXEvent extends AQuiXEvent { AXMLQuiXEvent(QuiXToken token) { super(token); } } public abstract static class AJSONQuiXEvent extends AQuiXEvent { AJSONQuiXEvent(QuiXToken token) { super(token); } } public abstract static class ARDFQuiXEvent extends AQuiXEvent { ARDFQuiXEvent(QuiXToken token) { super(token); } } public abstract static class ACSVQuiXEvent extends AQuiXEvent { ACSVQuiXEvent(QuiXToken token) { super(token); } } public static final class StartSequence extends AQuiXEvent { StartSequence() { super(QuiXToken.START_SEQUENCE); } @Override public String toString() { return this.type.toString(); } } public static final class EndSequence extends AQuiXEvent { EndSequence() { super(QuiXToken.END_SEQUENCE); } @Override public String toString() { return this.type.toString(); } } public static final class StartDocument extends AXMLQuiXEvent { private final QuiXCharStream uri; StartDocument(QuiXCharStream uri) { super(QuiXToken.START_DOCUMENT); this.uri = uri; createDocCount++; // System.out.println("START DOCUMENT"+uri); } public QuiXCharStream getURI() { return this.uri; } @Override public String toString() { return this.type + " " + this.uri; } } public static final class EndDocument extends AXMLQuiXEvent { private final QuiXCharStream uri; EndDocument(QuiXCharStream uri) { super(QuiXToken.END_DOCUMENT); this.uri = uri; createDocCount++; // System.out.println("END DOCUMENT"+uri); } public QuiXCharStream getURI() { return this.uri; } @Override public String toString() { return this.type + " " + this.uri; } } public static class StartJSON extends AJSONQuiXEvent { public StartJSON() { super(QuiXToken.START_JSON); } } public static class EndJSON extends AJSONQuiXEvent { public EndJSON() { super(QuiXToken.END_JSON); } } public static class StartObject extends AJSONQuiXEvent { public StartObject() { super(QuiXToken.START_OBJECT); } } public static class EndObject extends AJSONQuiXEvent { public EndObject() { super(QuiXToken.END_OBJECT); } } // start array is in JSON/YAML but also in CSV/TSV public static class StartArray extends AQuiXEvent { public StartArray() { super(QuiXToken.START_ARRAY); } } // start array is in JSON/YAML but also in CSV/TSV public static class EndArray extends AQuiXEvent { public EndArray() { super(QuiXToken.END_ARRAY); } } // Table CSV / TSV public static class StartTable extends ACSVQuiXEvent { public StartTable() { super(QuiXToken.START_TABLE); } } public static class EndTable extends ACSVQuiXEvent { public EndTable() { super(QuiXToken.END_TABLE); } } // RDF Triple public static class StartRDF extends ARDFQuiXEvent { public StartRDF() { super(QuiXToken.START_RDF); } } public static class EndRDF extends ARDFQuiXEvent { public EndRDF() { super(QuiXToken.END_RDF); } } public static class StartPredicate extends ARDFQuiXEvent { final QuiXCharStream name; public StartPredicate(QuiXCharStream name) { super(QuiXToken.START_PREDICATE); this.name = name; } } public static class EndPredicate extends ARDFQuiXEvent { final QuiXCharStream name; public EndPredicate(QuiXCharStream name) { super(QuiXToken.END_PREDICATE); this.name = name; } } public static class Subject extends ARDFQuiXEvent { final QuiXCharStream name; public Subject(QuiXCharStream name) { super(QuiXToken.SUBJECT); this.name = name; } } public static class Object extends ARDFQuiXEvent { final QuiXCharStream name; public Object(QuiXCharStream name) { super(QuiXToken.OBJECT); this.name = name; } } public static class Graph extends ARDFQuiXEvent { final QuiXCharStream name; public Graph(QuiXCharStream name) { super(QuiXToken.GRAPH); this.name = name; } } // JSON public static class AJSONValue extends AJSONQuiXEvent { AJSONValue(QuiXToken token) { super(token); } } public static class ValueNull extends AJSONValue { public ValueNull() { super(QuiXToken.VALUE_NULL); } } public static class ValueTrue extends AJSONValue { public ValueTrue() { super(QuiXToken.VALUE_TRUE); } } public static class ValueFalse extends AJSONValue { public ValueFalse() { super(QuiXToken.VALUE_FALSE); } } public static class ValueNumber extends AJSONValue { final double value; public ValueNumber(double value) { super(QuiXToken.VALUE_NUMBER); this.value = value; } } public static class ValueString extends AJSONValue { final QuiXCharStream value; public ValueString(QuiXCharStream value) { super(QuiXToken.VALUE_STRING); this.value = value; } } public static class KeyName extends AJSONQuiXEvent { private final QuiXCharStream name; KeyName(QuiXCharStream name) { super(QuiXToken.KEY_NAME); this.name = name; } } public static final class Namespace extends AXMLQuiXEvent { private final QuiXCharStream prefix; private final QuiXCharStream uri; Namespace(QuiXCharStream prefix, QuiXCharStream uri) { super(QuiXToken.NAMESPACE); this.prefix = prefix; this.uri = uri; } public QuiXCharStream getPrefix() { return this.prefix; } public QuiXCharStream getURI() { return this.uri; } @Override public String toString() { return this.type + " " + this.prefix + ":" + this.uri; } } public abstract static class NamedEvent extends AXMLQuiXEvent { private final QuiXQName qname; NamedEvent(QuiXQName qname, QuiXToken type) { super(type); this.qname = qname; } public QuiXCharStream getLocalName() { return this.qname.getLocalPart(); } public QuiXCharStream getFullName() { return (this.qname.getPrefix().isEmpty() ? QuiXCharStream.EMPTY : this.qname.getPrefix().append(":")) .append(this.qname.getLocalPart()); } public QuiXCharStream getURI() { return this.qname.getNamespaceURI(); } public QuiXCharStream getPrefix() { return this.qname.getPrefix(); } public QuiXQName getQName() { return this.qname; } } public static final class StartElement extends NamedEvent { StartElement(QuiXQName qname) { super(qname, QuiXToken.START_ELEMENT); // System.out.println("START ELEMENT"+localName); } @Override public String toString() { return this.type + " " + getLocalName(); } } public static final class EndElement extends NamedEvent { EndElement(QuiXQName qname) { super(qname, QuiXToken.END_ELEMENT); // System.out.println("END ELEMENT" + localName); } @Override public String toString() { return this.type + " " + getLocalName(); } } public static final class Attribute extends NamedEvent { private final QuiXCharStream value; Attribute(QuiXQName qname, QuiXCharStream value) { super(qname, QuiXToken.ATTRIBUTE); this.value = value; createAttrCount++; // System.out.println("ATTRIBUTE"); } public QuiXCharStream getValue() { return this.value; } @Override public String toString() { return this.type + " " + getLocalName(); } } public static final class Text extends AXMLQuiXEvent { private final QuiXCharStream data; Text(QuiXCharStream data) { super(QuiXToken.TEXT); this.data = data; // System.out.println("TEXT"); } public QuiXCharStream getData() { return this.data; } @Override public String toString() { return this.type + " " + getData(); } } public static final class PI extends AXMLQuiXEvent { private final QuiXCharStream target; private final QuiXCharStream data; PI(QuiXCharStream target, QuiXCharStream data) { super(QuiXToken.PROCESSING_INSTRUCTION); this.target = target; this.data = data; } public QuiXCharStream getTarget() { return this.target; } public QuiXCharStream getData() { return this.data; } @Override public String toString() { return this.type + " " + getTarget(); } } public static final class Comment extends AXMLQuiXEvent { private final QuiXCharStream data; Comment(QuiXCharStream data) { super(QuiXToken.COMMENT); this.data = data; } public QuiXCharStream getData() { return this.data; } @Override public String toString() { return this.type + " " + getData(); } } public NamedEvent asNamedEvent() { return (NamedEvent) this; } public StartSequence asStartSequence() { return (StartSequence) this; } public EndSequence asEndSequence() { return (EndSequence) this; } public Namespace asNamespace() { return (Namespace) this; } public StartElement asStartElement() { return (StartElement) this; } public EndElement asEndElement() { return (EndElement) this; } public StartDocument asStartDocument() { return (StartDocument) this; } public EndDocument asEndDocument() { return (EndDocument) this; } public Text asText() { return (Text) this; } public Comment asComment() { return (Comment) this; } public PI asPI() { return (PI) this; } public Attribute asAttribute() { return (Attribute) this; } @Override public QuiXToken getType() { return this.type; } /* get typed event */ private static StartSequence newStartSequence = SEQUENCE_CACHING_ENABLED ? new StartSequence() : null; public static AQuiXEvent getStartSequence() { createCallCount++; StartSequence result; result = SEQUENCE_CACHING_ENABLED ? newStartSequence : new StartSequence(); return result; } private static EndSequence newEndSequence = SEQUENCE_CACHING_ENABLED ? new EndSequence() : null; public static AQuiXEvent getEndSequence() { createCallCount++; EndSequence result; result = SEQUENCE_CACHING_ENABLED ? newEndSequence : new EndSequence(); return result; } private static Map<QuiXCharStream, StartDocument> startDocumentMap = DOCUMENT_CACHING_ENABLED ? new HashMap<QuiXCharStream, StartDocument>() : null; public static AXMLQuiXEvent getStartDocument(QuiXCharStream uri) { createCallCount++; StartDocument result; if (DOCUMENT_CACHING_ENABLED) { synchronized (startDocumentMap) { if (startDocumentMap.containsKey(uri)) { result = startDocumentMap.get(uri); } else { result = new StartDocument(uri); startDocumentMap.put(uri, result); } } } else { result = new StartDocument(uri); } return result; } private static Map<QuiXCharStream, EndDocument> endDocumentMap = DOCUMENT_CACHING_ENABLED ? new HashMap<QuiXCharStream, EndDocument>() : null; public static AXMLQuiXEvent getEndDocument(QuiXCharStream uri) { createCallCount++; EndDocument result; if (DOCUMENT_CACHING_ENABLED) { synchronized (endDocumentMap) { if (endDocumentMap.containsKey(uri)) { result = endDocumentMap.get(uri); } else { result = new EndDocument(uri); endDocumentMap.put(uri, result); } } } else { result = new EndDocument(uri); } return result; } public static Namespace getNamespace(QuiXCharStream prefix, QuiXCharStream uri) { return new Namespace(prefix == null ? QuiXCharStream.EMPTY : prefix, uri); } private static Map<QuiXCharStream, QuiXQName> qNameMap = NAME_CACHING_ENABLED ? new HashMap<QuiXCharStream, QuiXQName>() : null; private static QuiXQName getQName(QuiXCharStream localName, QuiXCharStream namespace, QuiXCharStream pref) { QuiXQName result; QuiXCharStream uri = namespace == null ? QuiXCharStream.EMPTY : namespace; QuiXCharStream prefix = pref == null ? QuiXCharStream.EMPTY : pref; if (NAME_CACHING_ENABLED) { QuiXCharStream key = localName; // here the prefix plays no role // if (prefix.length() > 0) key = prefix + ":" + localName; if (!uri.isEmpty()) key = QuiXCharStream.fromSequence("{").append(uri).append("}").append(key); synchronized (qNameMap) { if (qNameMap.containsKey(key)) { result = qNameMap.get(key); } else { result = new QuiXQName(uri, localName, prefix); qNameMap.put(key, result); } } } else { result = new QuiXQName(uri, localName, prefix); } return result; } private static Map<QuiXQName, StartElement> startElementMap = ELEMENT_CACHING_ENABLED ? new HashMap<QuiXQName, StartElement>() : null; public static AXMLQuiXEvent getStartElement(QuiXCharStream qName, QuiXCharStream namespace) { QuiXCharStream localName = qName; QuiXCharStream prefix = null; if (qName.contains(":")) { prefix = qName.substringBefore(":"); localName = qName.substringAfter(":"); } return getStartElement(localName, namespace, prefix); } public static AXMLQuiXEvent getStartElement(QuiXCharStream localName, QuiXCharStream namespace, QuiXCharStream prefix) { createCallCount++; StartElement result; QuiXQName qname = getQName(localName, namespace, prefix); if (ELEMENT_CACHING_ENABLED) { synchronized (startElementMap) { if (startElementMap.containsKey(qname)) { result = startElementMap.get(qname); } else { result = new StartElement(qname); startElementMap.put(qname, result); } } } else { result = new StartElement(qname); } return result; } private static Map<QuiXQName, EndElement> endElementMap = ELEMENT_CACHING_ENABLED ? new HashMap<QuiXQName, EndElement>() : null; public static AXMLQuiXEvent getEndElement(QuiXCharStream qName, QuiXCharStream namespace) { QuiXCharStream localName = qName; QuiXCharStream prefix = null; if (qName.contains(":")) { prefix = qName.substringBefore(":"); localName = qName.substringAfter(":"); } return getEndElement(localName, namespace, prefix); } public static AXMLQuiXEvent getEndElement(QuiXCharStream localName, QuiXCharStream namespace, QuiXCharStream prefix) { createCallCount++; EndElement result; QuiXQName qname = getQName(localName, namespace, prefix); if (ELEMENT_CACHING_ENABLED) { synchronized (endElementMap) { if (endElementMap.containsKey(qname)) { result = endElementMap.get(qname); } else { result = new EndElement(qname); endElementMap.put(qname, result); } } } else { result = new EndElement(qname); } return result; } public static AXMLQuiXEvent getAttribute(QuiXCharStream qName, QuiXCharStream namespace, QuiXCharStream value) { QuiXCharStream localName = qName; QuiXCharStream prefix = null; if (qName.contains(":")) { prefix = qName.substringBefore(":"); localName = qName.substringAfter(":"); } return getAttribute(localName, namespace, prefix, value); } public static AXMLQuiXEvent getAttribute(QuiXCharStream localName, QuiXCharStream namespace, QuiXCharStream prefix, QuiXCharStream value) { createCallCount++; return new Attribute(getQName(localName, namespace, prefix), value); } public static AXMLQuiXEvent getText(QuiXCharStream text) { createCallCount++; return new Text(text); } public static AXMLQuiXEvent getPI(QuiXCharStream target, QuiXCharStream data) { createCallCount++; return new PI(target, data); } public static AXMLQuiXEvent getComment(QuiXCharStream comment) { createCallCount++; return new Comment(comment); } // JSON public static AJSONQuiXEvent getStartJSON() { return new StartJSON(); } public static AJSONQuiXEvent getEndJSON() { return new EndJSON(); } public static AJSONQuiXEvent getStartObject() { return new StartObject(); } public static AJSONQuiXEvent getEndObject() { return new EndObject(); } public static AQuiXEvent getStartArray() { return new StartArray(); } public static AQuiXEvent getEndArray() { return new EndArray(); } public static AJSONQuiXEvent getKeyName(QuiXCharStream name) { return new KeyName(name); } public static AJSONQuiXEvent getValueNull() { return new ValueNull(); } public static AJSONQuiXEvent getValueTrue() { return new ValueTrue(); } public static AJSONQuiXEvent getValueFalse() { return new ValueFalse(); } public static AJSONQuiXEvent getValueNumber(double number) { return new ValueNumber(number); } public static AJSONQuiXEvent getValueString(QuiXCharStream str) { return new ValueString(str); } // CSV/TSV public static ACSVQuiXEvent getStartTable() { return new StartTable(); } public static ACSVQuiXEvent getEndTable() { return new EndTable(); } // RDF public static ARDFQuiXEvent getStartRDF() { return new StartRDF(); } public static ARDFQuiXEvent getEndRDF() { return new EndRDF(); } public static ARDFQuiXEvent getStartPredicate(QuiXCharStream name) { return new StartPredicate(name); } public static ARDFQuiXEvent getEndPredicate(QuiXCharStream name) { return new EndPredicate(name); } public static ARDFQuiXEvent getSubject(QuiXCharStream name) { return new Subject(name); } public static ARDFQuiXEvent getObject(QuiXCharStream name) { return new Object(name); } public static ARDFQuiXEvent getGraph(QuiXCharStream name) { return new Graph(name); } /* utilities */ public boolean isStartSequence() { return (this.type == QuiXToken.START_SEQUENCE); } public boolean isEndSequence() { return (this.type == QuiXToken.END_SEQUENCE); } public boolean isStartDocument() { return (this.type == QuiXToken.START_DOCUMENT); } public boolean isEndDocument() { return (this.type == QuiXToken.END_DOCUMENT); } public boolean isStartElement() { return (this.type == QuiXToken.START_ELEMENT); } public boolean isEndElement() { return (this.type == QuiXToken.END_ELEMENT); } public boolean isAttribute() { return (this.type == QuiXToken.ATTRIBUTE); } public boolean isText() { return (this.type == QuiXToken.TEXT); } public boolean isPI() { return (this.type == QuiXToken.PROCESSING_INSTRUCTION); } public boolean isComment() { return (this.type == QuiXToken.COMMENT); } public boolean isNamespace() { return (this.type == QuiXToken.NAMESPACE); } @Override public AQuiXEvent getEvent() { return this; } /* debugging */ public static long getCreateCount() { return createCount; } public static long getCreateDocCount() { return createDocCount; } public static long getCreateAttrCount() { return createAttrCount; } public static long getCreateCallCount() { return createCallCount; } public static void resetCreateCount() { createCount = 0; createDocCount = 0; createAttrCount = 0; createCallCount = 0; } }