Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

triggers redesign and new SAXTrigger

  • Loading branch information...
commit ea75c3c2c54f7786506e3db9b195c3b02b5a4cba 1 parent 0c5f79a
@shabanovd shabanovd authored
Showing with 1,647 additions and 1,994 deletions.
  1. +7 −88 extensions/fluent/src/org/exist/fluent/ListenerManager.java
  2. +421 −427 extensions/fluent/src/org/exist/fluent/Node.java
  3. +24 −22 extensions/fluent/src/org/exist/fluent/Trigger.java
  4. +107 −101 src/org/exist/Database.java
  5. +31 −71 src/org/exist/collections/Collection.java
  6. +34 −42 src/org/exist/collections/CollectionConfiguration.java
  7. +14 −16 src/org/exist/collections/IndexInfo.java
  8. +0 −56 src/org/exist/collections/triggers/AbstractTriggerProxies.java
  9. +18 −50 src/org/exist/collections/triggers/AbstractTriggerProxy.java
  10. +11 −14 src/org/exist/collections/triggers/AbstractTriggersVisitor.java
  11. +1 −3 src/org/exist/collections/triggers/CollectionTrigger.java
  12. +0 −36 src/org/exist/collections/triggers/CollectionTriggerProxies.java
  13. +4 −4 src/org/exist/collections/triggers/CollectionTriggerProxy.java
  14. +155 −0 src/org/exist/collections/triggers/CollectionTriggers.java
  15. +4 −72 src/org/exist/collections/triggers/CollectionTriggersVisitor.java
  16. +0 −96 src/org/exist/collections/triggers/ContentHandlerWrapper.java
  17. +3 −50 src/org/exist/collections/triggers/DocumentTrigger.java
  18. +0 −36 src/org/exist/collections/triggers/DocumentTriggerProxies.java
  19. +5 −8 src/org/exist/collections/triggers/DocumentTriggerProxy.java
  20. +364 −0 src/org/exist/collections/triggers/DocumentTriggers.java
  21. +4 −315 src/org/exist/collections/triggers/DocumentTriggersVisitor.java
  22. +3 −162 src/org/exist/collections/triggers/FilteringTrigger.java
  23. +0 −74 src/org/exist/collections/triggers/LexicalHandlerWrapper.java
  24. +211 −0 src/org/exist/collections/triggers/SAXTrigger.java
  25. +9 −10 src/org/exist/collections/triggers/STXTransformerTrigger.java
  26. +38 −40 src/org/exist/collections/triggers/Trigger.java
  27. +3 −4 src/org/exist/collections/triggers/TriggerProxy.java
  28. +65 −65 src/org/exist/collections/triggers/XQueryTrigger.java
  29. +21 −49 src/org/exist/storage/BrokerPool.java
  30. +69 −73 src/org/exist/storage/NativeBroker.java
  31. +14 −9 src/org/exist/xquery/update/Modification.java
  32. +7 −1 src/org/exist/xupdate/Modification.java
View
95 extensions/fluent/src/org/exist/fluent/ListenerManager.java
@@ -7,16 +7,12 @@
import org.exist.collections.Collection;
import org.exist.collections.triggers.CollectionTrigger;
import org.exist.collections.triggers.DocumentTrigger;
+import org.exist.collections.triggers.SAXTrigger;
import org.exist.collections.triggers.TriggerException;
import org.exist.dom.DocumentImpl;
import org.exist.storage.DBBroker;
import org.exist.storage.txn.Txn;
import org.exist.xmldb.XmldbURI;
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.Locator;
-import org.xml.sax.SAXException;
-import org.xml.sax.ext.LexicalHandler;
/**
* Internal class not for public use; needs to be public due to external instantiation requirements.
@@ -247,96 +243,15 @@ private void fire(List<ListenerWrapper> list, EventKey key, DocumentImpl doc, or
*
* @author <a href="mailto:piotr@ideanest.com">Piotr Kaminski</a>
*/
- public static class TriggerDispatcher implements DocumentTrigger, CollectionTrigger {
+ public static class TriggerDispatcher extends SAXTrigger implements DocumentTrigger, CollectionTrigger {
private static final Logger LOG = Logger.getLogger(TriggerDispatcher.class);
- private boolean validating;
- private ContentHandler contentHandler;
- private LexicalHandler lexicalHandler;
- public void configure(DBBroker broker, org.exist.collections.Collection parent, Map parameters) {
+ public void configure(DBBroker broker, org.exist.collections.Collection parent, Map<String, List<? extends Object>> parameters) {
// nothing to do
}
- public boolean isValidating() {
- return validating;
- }
- public void setValidating(boolean validating) {
- this.validating = validating;
- }
- public void setOutputHandler(ContentHandler handler) {
- this.contentHandler = handler;
- }
- public void setLexicalOutputHandler(LexicalHandler handler) {
- this.lexicalHandler = handler;
- }
- public ContentHandler getOutputHandler() {
- return contentHandler;
- }
- public ContentHandler getInputHandler() {
- return this;
- }
- public LexicalHandler getLexicalOutputHandler() {
- return lexicalHandler;
- }
- public LexicalHandler getLexicalInputHandler() {
- return this;
- }
public Logger getLogger() {
return LOG;
}
- public void characters(char[] ch, int start, int length) throws SAXException {
- contentHandler.characters(ch, start, length);
- }
- public void endDocument() throws SAXException {
- contentHandler.endDocument();
- }
- public void endElement(String uri, String localName, String qName) throws SAXException {
- contentHandler.endElement(uri, localName, qName);
- }
- public void endPrefixMapping(String prefix) throws SAXException {
- contentHandler.endPrefixMapping(prefix);
- }
- public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
- contentHandler.ignorableWhitespace(ch, start, length);
- }
- public void processingInstruction(String target, String data) throws SAXException {
- contentHandler.processingInstruction(target, data);
- }
- public void setDocumentLocator(Locator locator) {
- contentHandler.setDocumentLocator(locator);
- }
- public void skippedEntity(String name) throws SAXException {
- contentHandler.skippedEntity(name);
- }
- public void startDocument() throws SAXException {
- contentHandler.startDocument();
- }
- public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
- contentHandler.startElement(uri, localName, qName, atts);
- }
- public void startPrefixMapping(String prefix, String uri) throws SAXException {
- contentHandler.startPrefixMapping(prefix, uri);
- }
- public void comment(char[] ch, int start, int length) throws SAXException {
- lexicalHandler.comment(ch, start, length);
- }
- public void endCDATA() throws SAXException {
- lexicalHandler.endCDATA();
- }
- public void endDTD() throws SAXException {
- lexicalHandler.endDTD();
- }
- public void endEntity(String name) throws SAXException {
- lexicalHandler.endEntity(name);
- }
- public void startCDATA() throws SAXException {
- lexicalHandler.startCDATA();
- }
- public void startDTD(String name, String publicId, String systemId) throws SAXException {
- lexicalHandler.startDTD(name, publicId, systemId);
- }
- public void startEntity(String name) throws SAXException {
- lexicalHandler.startEntity(name);
- }
@Override
public void beforeCreateCollection(DBBroker broker, Txn transaction, XmldbURI uri) throws TriggerException {
@@ -432,10 +347,14 @@ public void afterDeleteDocument(DBBroker broker, Txn transaction, XmldbURI uri)
@Override
public void beforeUpdateDocumentMetadata(DBBroker broker, Txn txn, DocumentImpl document) throws TriggerException {
+ EventKey key = new EventKey(document.getURI().toString(), Trigger.BEFORE_UPDATE_META);
+ INSTANCE.fire(key, document, null, true);
}
@Override
public void afterUpdateDocumentMetadata(DBBroker broker, Txn txn, DocumentImpl document) throws TriggerException {
+ EventKey key = new EventKey(document.getURI().toString(), Trigger.AFTER_UPDATE_META);
+ INSTANCE.fire(key, document, null, true);
}
}
}
View
848 extensions/fluent/src/org/exist/fluent/Node.java
@@ -1,428 +1,422 @@
-package org.exist.fluent;
-
-import java.io.IOException;
-import java.util.*;
-
-import javax.xml.datatype.*;
-
-import org.apache.log4j.Logger;
-import org.exist.collections.Collection;
-import org.exist.collections.triggers.*;
-import org.exist.dom.*;
-import org.exist.storage.DBBroker;
-import org.exist.storage.io.VariableByteOutputStream;
-import org.exist.xquery.XPathException;
-import org.exist.xquery.value.*;
-import org.w3c.dom.*;
-
-/**
- * A node in the database. Nodes are most often contained in XML documents, but can also
- * be transient in-memory nodes created by a query.
- *
- * @author <a href="mailto:piotr@ideanest.com">Piotr Kaminski</a>
- */
-public class Node extends Item {
-
- private final static Logger LOG = Logger.getLogger(Collection.class);
-
- private XMLDocument document;
- final StaleMarker staleMarker = new StaleMarker();
-
- private Node() {}
-
- Node(org.exist.xquery.value.NodeValue item, NamespaceMap namespaceBindings, Database db) {
- super(item, namespaceBindings, db);
- if (item instanceof NodeProxy) {
- NodeProxy proxy = (NodeProxy) item;
- String docPath = proxy.getDocument().getURI().getCollectionPath();
- staleMarker.track(docPath.substring(0, docPath.lastIndexOf('/'))); // folder
- staleMarker.track(docPath); // document
- staleMarker.track(docPath + "#" + proxy.getNodeId()); // node
- }
- }
-
- @Override Sequence convertToSequence() {
- staleMarker.check();
- return super.convertToSequence();
- }
-
- public boolean extant() {
- return !staleMarker.stale();
- }
-
- org.w3c.dom.Node getDOMNode() {
- staleMarker.check();
- try {
- org.w3c.dom.Node domNode = ((NodeValue) item).getNode();
- if (domNode == null) throw new DatabaseException("unable to load node data");
- return domNode;
- } catch (org.exist.util.sanity.AssertFailure e) {
- throw new DatabaseException(e);
- }
- }
-
- /**
- * Return this node.
- *
- * @return this node
- */
- @Override public Node node() {
- return this;
- }
-
- @Override public Comparable<Object> comparableValue() {
- throw new DatabaseException("nodes are not comparable");
- }
-
- /**
- * Return whether this node represents the same node in the database as the given object.
- */
- @Override public boolean equals(Object o) {
- if (!(o instanceof Node)) return false;
- Node that = (Node) o;
- if (item == that.item) return true;
- if (this.item instanceof NodeProxy && that.item instanceof NodeProxy) {
- try {
- return ((NodeProxy) this.item).equals((NodeProxy) that.item);
- } catch (XPathException e) {
- // fall through to return false below
- }
- }
- return false;
- }
-
- /**
- * Warning: computing a node's hash code is surprisingly expensive, and the value is not cached.
- * You should not use nodes in situations where they might get hashed.
- */
- @Override public int hashCode() {
- return computeHashCode();
- }
-
- private int computeHashCode() {
- if (item instanceof NodeProxy) {
- NodeProxy proxy = (NodeProxy) item;
- VariableByteOutputStream buf = new VariableByteOutputStream();
- try {
- proxy.getNodeId().write(buf);
- } catch (IOException e) {
- throw new RuntimeException("unable to serialize node's id to compute hashCode", e);
- }
- return proxy.getDocument().getURI().hashCode() ^ Arrays.hashCode(buf.toByteArray());
- } else {
- return item.hashCode();
- }
- }
-
- /**
- * Return the namespace bindings in force in the scope of this node. Only works on nodes
- * that are XML elements. Namespaces reserved by the XML spec, and implicitly in scope
- * for all XML elements, are not reported.
- *
- * @return the namespace bindings in force for this node
- */
- public NamespaceMap inScopeNamespaces() {
- NamespaceMap namespaceMap = new NamespaceMap();
- for (Iterator<String> it = query().all(
- "for $prefix in in-scope-prefixes($_1) return ($prefix, namespace-uri-for-prefix($prefix, $_1))", this).values().iterator(); it.hasNext(); ) {
- String prefix = it.next(), namespace = it.next();
- if (!NamespaceMap.isReservedPrefix(prefix)) namespaceMap.put(prefix, namespace);
- }
- return namespaceMap;
- }
-
- /**
- * Compare the order of two nodes in a document.
- *
- * @param node the node to compare this one to
- * @return node 0 if this node is the same as the given node, a value less than 0 if it precedes the
- * given node in the document, and a value great than 0 if it follows the given node in the document
- * @throws DatabaseException if this node and the given one are not in the same document
- */
- public int compareDocumentOrderTo(Node node) {
- if (this.item == node.item) return 0;
- NodeValue nv1 = (NodeValue) this.item, nv2 = (NodeValue) node.item;
- if (nv1.getImplementationType() != nv2.getImplementationType())
- throw new DatabaseException("can't compare different node types, since they can never be in the same document");
- if (nv1.getImplementationType() == NodeValue.PERSISTENT_NODE) {
- NodeProxy n1 = (NodeProxy) item, n2 = (NodeProxy) node.item;
- if (n1.getDocument().getDocId() != n2.getDocument().getDocId())
- throw new DatabaseException("can't compare document order of nodes in disparate documents: this node is in " + document() + " and the argument node in " + node.document());
- if (n1.getNodeId().equals(n2.getNodeId())) return 0;
- try {
- return n1.before(n2, false) ? -1 : +1;
- } catch (XPathException e) {
- throw new DatabaseException("unable to compare nodes", e);
- }
- } else if (nv1.getImplementationType() == NodeValue.IN_MEMORY_NODE) {
- org.exist.memtree.NodeImpl n1 = (org.exist.memtree.NodeImpl) nv1, n2 = (org.exist.memtree.NodeImpl) nv2;
- if (n1.getDocument() != n2.getDocument())
- throw new DatabaseException("can't compare document order of in-memory nodes created separately");
- try {
- return n1.before(n2, false) ? -1 : +1;
- } catch (XPathException e) {
- throw new DatabaseException("unable to compare nodes", e);
- }
- } else {
- throw new DatabaseException("unknown node implementation type: " + nv1.getImplementationType());
- }
- }
-
- /**
- * Return the document to which this node belongs.
- *
- * @return the document to which this node belongs
- * @throws UnsupportedOperationException if this node does not belong to a document
- */
- public XMLDocument document() {
- staleMarker.check();
- if (document == null) try {
- document = Document.newInstance(((NodeProxy) item).getDocument(), this).xml();
- } catch (ClassCastException e) {
- throw new UnsupportedOperationException("node is not part of a document in the database");
- }
- return document;
- }
-
- /**
- * Return a builder that will append elements to this node's children. The builder will return the
- * appended node if a single node was appended, otherwise <code>null</code>.
- *
- * @return a builder that will append nodes to this node
- */
- public ElementBuilder<Node> append() {
- staleMarker.check(); // do an early check to fail-fast, we'll check again on completion
- try {
- final StoredNode node = (StoredNode) getDOMNode();
- return new ElementBuilder<Node>(namespaceBindings, true, new ElementBuilder.CompletedCallback<Node>() {
- public Node completed(org.w3c.dom.Node[] nodes) {
- Transaction tx = db.requireTransactionWithBroker();
- try {
- tx.lockWrite(node.getDocument());
- DocumentTrigger trigger = fireTriggerBefore(tx);
- node.appendChildren(tx.tx, toNodeList(nodes), 0);
- StoredNode result = (StoredNode) node.getLastChild();
- touchDefragAndFireTriggerAfter(tx, trigger);
- tx.commit();
- if (result == null) return null;
- NodeProxy proxy = new NodeProxy((DocumentImpl) result.getOwnerDocument(), result.getNodeId(), result.getNodeType(), result.getInternalAddress());
- return new Node(proxy, namespaceBindings.extend(), db);
- } catch (DOMException e) {
- throw new DatabaseException(e);
- } catch (TriggerException e) {
- throw new DatabaseException("append aborted by listener", e);
- } finally {
- tx.abortIfIncomplete();
- }
- }
- });
- } catch (ClassCastException e) {
- if (getDOMNode() instanceof org.exist.memtree.NodeImpl) {
- throw new UnsupportedOperationException("appends to in-memory nodes are not supported");
- } else {
- throw new UnsupportedOperationException("cannot append to a " + Type.getTypeName(item.getType()));
- }
- }
- }
-
- /**
- * Delete this node from its parent. This can delete an element from a document,
- * or an attribute from an element, etc. Trying to delete the root element of a
- * document will delete the document instead. If the node cannot be found, assume
- * it's already been deleted and return silently.
- */
- public void delete() {
- org.w3c.dom.Node child;
- try {
- child = getDOMNode();
- } catch (DatabaseException e) {
- return;
- }
- NodeImpl parent = (NodeImpl) child.getParentNode();
- if (child instanceof org.w3c.dom.Document || parent instanceof org.w3c.dom.Document) {
- document().delete();
- } else if (parent == null) {
- throw new DatabaseException("cannot delete node with no parent");
- } else {
- Transaction tx = db.requireTransactionWithBroker();
- try {
- if (parent instanceof StoredNode) tx.lockWrite(((StoredNode) parent).getDocument());
- DocumentTrigger trigger = fireTriggerBefore(tx);
- parent.removeChild(tx.tx, child);
- touchDefragAndFireTriggerAfter(tx, trigger);
- tx.commit();
- } catch (DOMException e) {
- throw new DatabaseException(e);
- } catch (TriggerException e) {
- throw new DatabaseException("delete aborted by listener", e);
- } finally {
- tx.abortIfIncomplete();
- }
- }
- }
-
- /**
- * Return the name of this node, in the "prefix:localName" form.
- *
- * @return the name of this node
- */
- public String name() {
- return getDOMNode().getNodeName();
- }
-
- /**
- * Return the qualified name of this node, including its namespace URI, local name and prefix.
- *
- * @return the qname of this node
- */
- public QName qname() {
- org.w3c.dom.Node node = getDOMNode();
- String localName = node.getLocalName();
- if (localName == null) localName = node.getNodeName();
- return new QName(node.getNamespaceURI(), localName, node.getPrefix());
- }
-
- /**
- * Return a builder that will replace this node. The builder returns <code>null</code>.
- *
- * @return a builder that will replace this node
- * @throws UnsupportedOperationException if the node does not have a parent
- */
- public ElementBuilder<?> replace() {
- // TODO: right now, can only replace an element; what about other nodes?
- // TODO: right now, can only replace with a single node, investigate multiple replace
- try {
- final NodeImpl oldNode = (NodeImpl) getDOMNode();
- if (oldNode.getParentNode() == null) throw new UnsupportedOperationException("cannot replace a " + Type.getTypeName(item.getType()) + " with no parent");
- if (oldNode.getParentNode().getNodeType() == org.w3c.dom.Node.DOCUMENT_NODE)
- return document().folder().documents().build(Name.overwrite(db, document().name()));
- return new ElementBuilder<Object>(namespaceBindings, false, new ElementBuilder.CompletedCallback<Object>() {
- public Object completed(org.w3c.dom.Node[] nodes) {
- assert nodes.length == 1;
- Transaction tx = db.requireTransactionWithBroker();
- try {
- DocumentImpl doc = (DocumentImpl) oldNode.getOwnerDocument();
- tx.lockWrite(doc);
- DocumentTrigger trigger = fireTriggerBefore(tx);
- ((NodeImpl) oldNode.getParentNode()).replaceChild(tx.tx, nodes[0], oldNode);
- touchDefragAndFireTriggerAfter(tx, trigger);
- tx.commit();
- // no point in returning the old node; we'd rather return the newly inserted one,
- // but it's not easily available
- return null;
- } catch (DOMException e) {
- throw new DatabaseException(e);
- } catch (TriggerException e) {
- throw new DatabaseException("append aborted by listener", e);
- } finally {
- tx.abortIfIncomplete();
- }
- }
- });
- } catch (ClassCastException e) {
- if (getDOMNode() instanceof org.exist.memtree.NodeImpl) {
- throw new UnsupportedOperationException("replacement of in-memory nodes is not supported");
- } else {
- throw new UnsupportedOperationException("cannot replace a " + Type.getTypeName(item.getType()));
- }
- }
- }
-
- /**
- * Return a builder for updating the attribute values of this element.
- *
- * @return an attribute builder for this element
- * @throws UnsupportedOperationException if this node is not an element
- */
- public AttributeBuilder update() {
- try {
- final ElementImpl elem = (ElementImpl) getDOMNode();
- return new AttributeBuilder(elem, namespaceBindings, new AttributeBuilder.CompletedCallback() {
- public void completed(NodeList removeList, NodeList addList) {
- Transaction tx = db.requireTransactionWithBroker();
- try {
- DocumentImpl doc = (DocumentImpl) elem.getOwnerDocument();
- tx.lockWrite(doc);
- DocumentTrigger trigger = fireTriggerBefore(tx);
- elem.removeAppendAttributes(tx.tx, removeList, addList);
- touchDefragAndFireTriggerAfter(tx, trigger);
- tx.commit();
- } catch (TriggerException e) {
- throw new DatabaseException("append aborted by listener", e);
- } finally {
- tx.abortIfIncomplete();
- }
- }
- });
- } catch (ClassCastException e) {
- if (getDOMNode() instanceof org.exist.memtree.ElementImpl) {
- throw new UnsupportedOperationException("updates on in-memory nodes are not supported");
- } else {
- throw new UnsupportedOperationException("cannot update attributes on a " + Type.getTypeName(item.getType()));
- }
- }
- }
-
- private DocumentTrigger fireTriggerBefore(Transaction tx) throws TriggerException {
- if (!(item instanceof NodeProxy)) return null;
- DocumentImpl docimpl = ((NodeProxy) item).getDocument();
-// try {
- DocumentTrigger trigger = docimpl.getCollection().getConfiguration(tx.broker).getDocumentTriggerProxies().instantiateVisitor(tx.broker);
- if (trigger == null) return null;
-
- trigger.beforeUpdateDocument(tx.broker, tx.tx, docimpl);
-
- return trigger;
-// } catch (CollectionConfigurationException e) {
-// throw new DatabaseException(e);
-// }
- }
-
- private void touchDefragAndFireTriggerAfter(Transaction tx, DocumentTrigger trigger) throws TriggerException {
- DocumentImpl doc = ((NodeProxy) item).getDocument();
- doc.getMetadata().setLastModified(System.currentTimeMillis());
- tx.broker.storeXMLResource(tx.tx, doc);
- if (item instanceof NodeProxy) Database.queueDefrag(((NodeProxy) item).getDocument());
- if (trigger == null) return;
- DocumentImpl docimpl = ((NodeProxy) item).getDocument();
-
- trigger.afterUpdateDocument(tx.broker, tx.tx, docimpl);
- }
-
- static NodeList toNodeList(final org.w3c.dom.Node[] nodes) {
- return new NodeList() {
- public int getLength() {return nodes.length;}
- public org.w3c.dom.Node item(int index) {return nodes[index];}
- };
- }
-
- /**
- * A null node, used as a placeholder where an actual <code>null</code> would be inappropriate.
- */
- static final Node NULL = new Node() {
- @Override public ElementBuilder<Node> append() {throw new UnsupportedOperationException("cannot append to a null resource");}
- @Override public void delete() {}
- @Override public XMLDocument document() {throw new UnsupportedOperationException("null resource does not have a document");}
- @Override public String name() {throw new UnsupportedOperationException("null resource does not have a name");}
- @Override public QName qname() {throw new UnsupportedOperationException("null resource does not have a qname");}
- @Override public ElementBuilder<?> replace() {throw new UnsupportedOperationException("cannot replace a null resource");}
- @Override public AttributeBuilder update() {throw new UnsupportedOperationException("cannot update a null resource");}
-
- @Override public boolean booleanValue() {return Item.NULL.booleanValue();}
- @Override public double doubleValue() {return Item.NULL.doubleValue();}
- @Override public int intValue() {return Item.NULL.intValue();}
- @Override public long longValue() {return Item.NULL.longValue();}
- @Override public Duration durationValue() {return Item.NULL.durationValue();}
- @Override public XMLGregorianCalendar dateTimeValue() {return Item.NULL.dateTimeValue();}
- @Override public Date instantValue() {return Item.NULL.instantValue();}
- @Override public Node node() {return Item.NULL.node();}
- @Override public boolean extant() {return Item.NULL.extant();}
- @Override public QueryService query() {return Item.NULL.query();}
- @Override public String value() {return Item.NULL.value();}
- @Override public String valueWithDefault(String defaultValue) {return Item.NULL.value();}
- @Override Sequence convertToSequence() {return Item.NULL.convertToSequence();}
-
- @Override public String toString() { return "NULL Node";}
- };
-
+package org.exist.fluent;
+
+import java.io.IOException;
+import java.util.*;
+
+import javax.xml.datatype.*;
+
+import org.exist.collections.Collection;
+import org.exist.collections.triggers.*;
+import org.exist.dom.*;
+import org.exist.storage.io.VariableByteOutputStream;
+import org.exist.xquery.XPathException;
+import org.exist.xquery.value.*;
+import org.w3c.dom.*;
+
+/**
+ * A node in the database. Nodes are most often contained in XML documents, but can also
+ * be transient in-memory nodes created by a query.
+ *
+ * @author <a href="mailto:piotr@ideanest.com">Piotr Kaminski</a>
+ */
+public class Node extends Item {
+
+ private XMLDocument document;
+ final StaleMarker staleMarker = new StaleMarker();
+
+ private Node() {}
+
+ Node(org.exist.xquery.value.NodeValue item, NamespaceMap namespaceBindings, Database db) {
+ super(item, namespaceBindings, db);
+ if (item instanceof NodeProxy) {
+ NodeProxy proxy = (NodeProxy) item;
+ String docPath = proxy.getDocument().getURI().getCollectionPath();
+ staleMarker.track(docPath.substring(0, docPath.lastIndexOf('/'))); // folder
+ staleMarker.track(docPath); // document
+ staleMarker.track(docPath + "#" + proxy.getNodeId()); // node
+ }
+ }
+
+ @Override Sequence convertToSequence() {
+ staleMarker.check();
+ return super.convertToSequence();
+ }
+
+ public boolean extant() {
+ return !staleMarker.stale();
+ }
+
+ org.w3c.dom.Node getDOMNode() {
+ staleMarker.check();
+ try {
+ org.w3c.dom.Node domNode = ((NodeValue) item).getNode();
+ if (domNode == null) throw new DatabaseException("unable to load node data");
+ return domNode;
+ } catch (org.exist.util.sanity.AssertFailure e) {
+ throw new DatabaseException(e);
+ }
+ }
+
+ /**
+ * Return this node.
+ *
+ * @return this node
+ */
+ @Override public Node node() {
+ return this;
+ }
+
+ @Override public Comparable<Object> comparableValue() {
+ throw new DatabaseException("nodes are not comparable");
+ }
+
+ /**
+ * Return whether this node represents the same node in the database as the given object.
+ */
+ @Override public boolean equals(Object o) {
+ if (!(o instanceof Node)) return false;
+ Node that = (Node) o;
+ if (item == that.item) return true;
+ if (this.item instanceof NodeProxy && that.item instanceof NodeProxy) {
+ try {
+ return ((NodeProxy) this.item).equals((NodeProxy) that.item);
+ } catch (XPathException e) {
+ // fall through to return false below
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Warning: computing a node's hash code is surprisingly expensive, and the value is not cached.
+ * You should not use nodes in situations where they might get hashed.
+ */
+ @Override public int hashCode() {
+ return computeHashCode();
+ }
+
+ private int computeHashCode() {
+ if (item instanceof NodeProxy) {
+ NodeProxy proxy = (NodeProxy) item;
+ VariableByteOutputStream buf = new VariableByteOutputStream();
+ try {
+ proxy.getNodeId().write(buf);
+ } catch (IOException e) {
+ throw new RuntimeException("unable to serialize node's id to compute hashCode", e);
+ }
+ return proxy.getDocument().getURI().hashCode() ^ Arrays.hashCode(buf.toByteArray());
+ } else {
+ return item.hashCode();
+ }
+ }
+
+ /**
+ * Return the namespace bindings in force in the scope of this node. Only works on nodes
+ * that are XML elements. Namespaces reserved by the XML spec, and implicitly in scope
+ * for all XML elements, are not reported.
+ *
+ * @return the namespace bindings in force for this node
+ */
+ public NamespaceMap inScopeNamespaces() {
+ NamespaceMap namespaceMap = new NamespaceMap();
+ for (Iterator<String> it = query().all(
+ "for $prefix in in-scope-prefixes($_1) return ($prefix, namespace-uri-for-prefix($prefix, $_1))", this).values().iterator(); it.hasNext(); ) {
+ String prefix = it.next(), namespace = it.next();
+ if (!NamespaceMap.isReservedPrefix(prefix)) namespaceMap.put(prefix, namespace);
+ }
+ return namespaceMap;
+ }
+
+ /**
+ * Compare the order of two nodes in a document.
+ *
+ * @param node the node to compare this one to
+ * @return node 0 if this node is the same as the given node, a value less than 0 if it precedes the
+ * given node in the document, and a value great than 0 if it follows the given node in the document
+ * @throws DatabaseException if this node and the given one are not in the same document
+ */
+ public int compareDocumentOrderTo(Node node) {
+ if (this.item == node.item) return 0;
+ NodeValue nv1 = (NodeValue) this.item, nv2 = (NodeValue) node.item;
+ if (nv1.getImplementationType() != nv2.getImplementationType())
+ throw new DatabaseException("can't compare different node types, since they can never be in the same document");
+ if (nv1.getImplementationType() == NodeValue.PERSISTENT_NODE) {
+ NodeProxy n1 = (NodeProxy) item, n2 = (NodeProxy) node.item;
+ if (n1.getDocument().getDocId() != n2.getDocument().getDocId())
+ throw new DatabaseException("can't compare document order of nodes in disparate documents: this node is in " + document() + " and the argument node in " + node.document());
+ if (n1.getNodeId().equals(n2.getNodeId())) return 0;
+ try {
+ return n1.before(n2, false) ? -1 : +1;
+ } catch (XPathException e) {
+ throw new DatabaseException("unable to compare nodes", e);
+ }
+ } else if (nv1.getImplementationType() == NodeValue.IN_MEMORY_NODE) {
+ org.exist.memtree.NodeImpl n1 = (org.exist.memtree.NodeImpl) nv1, n2 = (org.exist.memtree.NodeImpl) nv2;
+ if (n1.getDocument() != n2.getDocument())
+ throw new DatabaseException("can't compare document order of in-memory nodes created separately");
+ try {
+ return n1.before(n2, false) ? -1 : +1;
+ } catch (XPathException e) {
+ throw new DatabaseException("unable to compare nodes", e);
+ }
+ } else {
+ throw new DatabaseException("unknown node implementation type: " + nv1.getImplementationType());
+ }
+ }
+
+ /**
+ * Return the document to which this node belongs.
+ *
+ * @return the document to which this node belongs
+ * @throws UnsupportedOperationException if this node does not belong to a document
+ */
+ public XMLDocument document() {
+ staleMarker.check();
+ if (document == null) try {
+ document = Document.newInstance(((NodeProxy) item).getDocument(), this).xml();
+ } catch (ClassCastException e) {
+ throw new UnsupportedOperationException("node is not part of a document in the database");
+ }
+ return document;
+ }
+
+ /**
+ * Return a builder that will append elements to this node's children. The builder will return the
+ * appended node if a single node was appended, otherwise <code>null</code>.
+ *
+ * @return a builder that will append nodes to this node
+ */
+ public ElementBuilder<Node> append() {
+ staleMarker.check(); // do an early check to fail-fast, we'll check again on completion
+ try {
+ final StoredNode node = (StoredNode) getDOMNode();
+ return new ElementBuilder<Node>(namespaceBindings, true, new ElementBuilder.CompletedCallback<Node>() {
+ public Node completed(org.w3c.dom.Node[] nodes) {
+ Transaction tx = db.requireTransactionWithBroker();
+ try {
+ tx.lockWrite(node.getDocument());
+ DocumentTrigger trigger = fireTriggerBefore(tx);
+ node.appendChildren(tx.tx, toNodeList(nodes), 0);
+ StoredNode result = (StoredNode) node.getLastChild();
+ touchDefragAndFireTriggerAfter(tx, trigger);
+ tx.commit();
+ if (result == null) return null;
+ NodeProxy proxy = new NodeProxy((DocumentImpl) result.getOwnerDocument(), result.getNodeId(), result.getNodeType(), result.getInternalAddress());
+ return new Node(proxy, namespaceBindings.extend(), db);
+ } catch (DOMException e) {
+ throw new DatabaseException(e);
+ } catch (TriggerException e) {
+ throw new DatabaseException("append aborted by listener", e);
+ } finally {
+ tx.abortIfIncomplete();
+ }
+ }
+ });
+ } catch (ClassCastException e) {
+ if (getDOMNode() instanceof org.exist.memtree.NodeImpl) {
+ throw new UnsupportedOperationException("appends to in-memory nodes are not supported");
+ } else {
+ throw new UnsupportedOperationException("cannot append to a " + Type.getTypeName(item.getType()));
+ }
+ }
+ }
+
+ /**
+ * Delete this node from its parent. This can delete an element from a document,
+ * or an attribute from an element, etc. Trying to delete the root element of a
+ * document will delete the document instead. If the node cannot be found, assume
+ * it's already been deleted and return silently.
+ */
+ public void delete() {
+ org.w3c.dom.Node child;
+ try {
+ child = getDOMNode();
+ } catch (DatabaseException e) {
+ return;
+ }
+ NodeImpl parent = (NodeImpl) child.getParentNode();
+ if (child instanceof org.w3c.dom.Document || parent instanceof org.w3c.dom.Document) {
+ document().delete();
+ } else if (parent == null) {
+ throw new DatabaseException("cannot delete node with no parent");
+ } else {
+ Transaction tx = db.requireTransactionWithBroker();
+ try {
+ if (parent instanceof StoredNode) tx.lockWrite(((StoredNode) parent).getDocument());
+ DocumentTrigger trigger = fireTriggerBefore(tx);
+ parent.removeChild(tx.tx, child);
+ touchDefragAndFireTriggerAfter(tx, trigger);
+ tx.commit();
+ } catch (DOMException e) {
+ throw new DatabaseException(e);
+ } catch (TriggerException e) {
+ throw new DatabaseException("delete aborted by listener", e);
+ } finally {
+ tx.abortIfIncomplete();
+ }
+ }
+ }
+
+ /**
+ * Return the name of this node, in the "prefix:localName" form.
+ *
+ * @return the name of this node
+ */
+ public String name() {
+ return getDOMNode().getNodeName();
+ }
+
+ /**
+ * Return the qualified name of this node, including its namespace URI, local name and prefix.
+ *
+ * @return the qname of this node
+ */
+ public QName qname() {
+ org.w3c.dom.Node node = getDOMNode();
+ String localName = node.getLocalName();
+ if (localName == null) localName = node.getNodeName();
+ return new QName(node.getNamespaceURI(), localName, node.getPrefix());
+ }
+
+ /**
+ * Return a builder that will replace this node. The builder returns <code>null</code>.
+ *
+ * @return a builder that will replace this node
+ * @throws UnsupportedOperationException if the node does not have a parent
+ */
+ public ElementBuilder<?> replace() {
+ // TODO: right now, can only replace an element; what about other nodes?
+ // TODO: right now, can only replace with a single node, investigate multiple replace
+ try {
+ final NodeImpl oldNode = (NodeImpl) getDOMNode();
+ if (oldNode.getParentNode() == null) throw new UnsupportedOperationException("cannot replace a " + Type.getTypeName(item.getType()) + " with no parent");
+ if (oldNode.getParentNode().getNodeType() == org.w3c.dom.Node.DOCUMENT_NODE)
+ return document().folder().documents().build(Name.overwrite(db, document().name()));
+ return new ElementBuilder<Object>(namespaceBindings, false, new ElementBuilder.CompletedCallback<Object>() {
+ public Object completed(org.w3c.dom.Node[] nodes) {
+ assert nodes.length == 1;
+ Transaction tx = db.requireTransactionWithBroker();
+ try {
+ DocumentImpl doc = (DocumentImpl) oldNode.getOwnerDocument();
+ tx.lockWrite(doc);
+ DocumentTrigger trigger = fireTriggerBefore(tx);
+ ((NodeImpl) oldNode.getParentNode()).replaceChild(tx.tx, nodes[0], oldNode);
+ touchDefragAndFireTriggerAfter(tx, trigger);
+ tx.commit();
+ // no point in returning the old node; we'd rather return the newly inserted one,
+ // but it's not easily available
+ return null;
+ } catch (DOMException e) {
+ throw new DatabaseException(e);
+ } catch (TriggerException e) {
+ throw new DatabaseException("append aborted by listener", e);
+ } finally {
+ tx.abortIfIncomplete();
+ }
+ }
+ });
+ } catch (ClassCastException e) {
+ if (getDOMNode() instanceof org.exist.memtree.NodeImpl) {
+ throw new UnsupportedOperationException("replacement of in-memory nodes is not supported");
+ } else {
+ throw new UnsupportedOperationException("cannot replace a " + Type.getTypeName(item.getType()));
+ }
+ }
+ }
+
+ /**
+ * Return a builder for updating the attribute values of this element.
+ *
+ * @return an attribute builder for this element
+ * @throws UnsupportedOperationException if this node is not an element
+ */
+ public AttributeBuilder update() {
+ try {
+ final ElementImpl elem = (ElementImpl) getDOMNode();
+ return new AttributeBuilder(elem, namespaceBindings, new AttributeBuilder.CompletedCallback() {
+ public void completed(NodeList removeList, NodeList addList) {
+ Transaction tx = db.requireTransactionWithBroker();
+ try {
+ DocumentImpl doc = (DocumentImpl) elem.getOwnerDocument();
+ tx.lockWrite(doc);
+ DocumentTrigger trigger = fireTriggerBefore(tx);
+ elem.removeAppendAttributes(tx.tx, removeList, addList);
+ touchDefragAndFireTriggerAfter(tx, trigger);
+ tx.commit();
+ } catch (TriggerException e) {
+ throw new DatabaseException("append aborted by listener", e);
+ } finally {
+ tx.abortIfIncomplete();
+ }
+ }
+ });
+ } catch (ClassCastException e) {
+ if (getDOMNode() instanceof org.exist.memtree.ElementImpl) {
+ throw new UnsupportedOperationException("updates on in-memory nodes are not supported");
+ } else {
+ throw new UnsupportedOperationException("cannot update attributes on a " + Type.getTypeName(item.getType()));
+ }
+ }
+ }
+
+ private DocumentTrigger fireTriggerBefore(Transaction tx) throws TriggerException {
+ if (!(item instanceof NodeProxy)) return null;
+
+ DocumentImpl docimpl = ((NodeProxy) item).getDocument();
+ Collection col = docimpl.getCollection();
+
+ DocumentTrigger trigger = new DocumentTriggers(tx.broker, null, col, col.getConfiguration(tx.broker));
+
+ trigger.beforeUpdateDocument(tx.broker, tx.tx, docimpl);
+
+ return trigger;
+ }
+
+ private void touchDefragAndFireTriggerAfter(Transaction tx, DocumentTrigger trigger) throws TriggerException {
+ DocumentImpl doc = ((NodeProxy) item).getDocument();
+ doc.getMetadata().setLastModified(System.currentTimeMillis());
+ tx.broker.storeXMLResource(tx.tx, doc);
+ if (item instanceof NodeProxy) Database.queueDefrag(((NodeProxy) item).getDocument());
+ if (trigger == null) return;
+ DocumentImpl docimpl = ((NodeProxy) item).getDocument();
+
+ trigger.afterUpdateDocument(tx.broker, tx.tx, docimpl);
+ }
+
+ static NodeList toNodeList(final org.w3c.dom.Node[] nodes) {
+ return new NodeList() {
+ public int getLength() {return nodes.length;}
+ public org.w3c.dom.Node item(int index) {return nodes[index];}
+ };
+ }
+
+ /**
+ * A null node, used as a placeholder where an actual <code>null</code> would be inappropriate.
+ */
+ static final Node NULL = new Node() {
+ @Override public ElementBuilder<Node> append() {throw new UnsupportedOperationException("cannot append to a null resource");}
+ @Override public void delete() {}
+ @Override public XMLDocument document() {throw new UnsupportedOperationException("null resource does not have a document");}
+ @Override public String name() {throw new UnsupportedOperationException("null resource does not have a name");}
+ @Override public QName qname() {throw new UnsupportedOperationException("null resource does not have a qname");}
+ @Override public ElementBuilder<?> replace() {throw new UnsupportedOperationException("cannot replace a null resource");}
+ @Override public AttributeBuilder update() {throw new UnsupportedOperationException("cannot update a null resource");}
+
+ @Override public boolean booleanValue() {return Item.NULL.booleanValue();}
+ @Override public double doubleValue() {return Item.NULL.doubleValue();}
+ @Override public int intValue() {return Item.NULL.intValue();}
+ @Override public long longValue() {return Item.NULL.longValue();}
+ @Override public Duration durationValue() {return Item.NULL.durationValue();}
+ @Override public XMLGregorianCalendar dateTimeValue() {return Item.NULL.dateTimeValue();}
+ @Override public Date instantValue() {return Item.NULL.instantValue();}
+ @Override public Node node() {return Item.NULL.node();}
+ @Override public boolean extant() {return Item.NULL.extant();}
+ @Override public QueryService query() {return Item.NULL.query();}
+ @Override public String value() {return Item.NULL.value();}
+ @Override public String valueWithDefault(String defaultValue) {return Item.NULL.value();}
+ @Override Sequence convertToSequence() {return Item.NULL.convertToSequence();}
+
+ @Override public String toString() { return "NULL Node";}
+ };
+
}
View
46 extensions/fluent/src/org/exist/fluent/Trigger.java
@@ -1,22 +1,24 @@
-package org.exist.fluent;
-
-/**
- * An action being undertaken on the database, used to characterize an event.
- * Note that for folders, <code>UPDATE</code> means rename.
- *
- * @author <a href="mailto:piotr@ideanest.com">Piotr Kaminski</a>
- */
-public enum Trigger {
- BEFORE_STORE,
- AFTER_STORE,
- BEFORE_CREATE,
- AFTER_CREATE,
- BEFORE_UPDATE,
- AFTER_UPDATE,
- BEFORE_RENAME,
- AFTER_RENAME,
- BEFORE_MOVE,
- AFTER_MOVE,
- BEFORE_REMOVE,
- AFTER_REMOVE
-}
+package org.exist.fluent;
+
+/**
+ * An action being undertaken on the database, used to characterize an event.
+ * Note that for folders, <code>UPDATE</code> means rename.
+ *
+ * @author <a href="mailto:piotr@ideanest.com">Piotr Kaminski</a>
+ */
+public enum Trigger {
+ BEFORE_STORE,
+ AFTER_STORE,
+ BEFORE_CREATE,
+ AFTER_CREATE,
+ BEFORE_UPDATE,
+ AFTER_UPDATE,
+ BEFORE_RENAME,
+ AFTER_RENAME,
+ BEFORE_MOVE,
+ AFTER_MOVE,
+ BEFORE_REMOVE,
+ AFTER_REMOVE,
+ BEFORE_UPDATE_META,
+ AFTER_UPDATE_META
+}
View
208 src/org/exist/Database.java
@@ -1,6 +1,6 @@
/*
* eXist Open Source Native XML Database
- * Copyright (C) 2010 The eXist Project
+ * Copyright (C) 2001-2014 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
@@ -16,18 +16,16 @@
* 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;
import java.io.File;
import java.util.Collection;
-import java.util.Observer;
import org.exist.collections.CollectionConfigurationManager;
import org.exist.collections.triggers.CollectionTrigger;
import org.exist.collections.triggers.DocumentTrigger;
+import org.exist.collections.triggers.TriggerProxy;
import org.exist.debuggee.Debuggee;
import org.exist.dom.SymbolTable;
import org.exist.indexing.IndexManager;
@@ -50,131 +48,139 @@
* Database controller, all operation synchronized by this instance. (singleton)
*
* @author <a href="mailto:shabanovd@gmail.com">Dmitriy Shabanov</a>
- *
+ *
*/
public interface Database {
- //TODO: javadocs
-
- public String getId();
-
- /**
- *
- * @return SecurityManager
- */
- public SecurityManager getSecurityManager();
+ // TODO: javadocs
- /**
- *
- * @return IndexManager
- */
- public IndexManager getIndexManager();
+ public String getId();
- /**
- *
- * @return TransactionManager
- */
- public TransactionManager getTransactionManager();
+ /**
+ *
+ * @return SecurityManager
+ */
+ public SecurityManager getSecurityManager();
- /**
- *
- * @return CacheManager
- */
- public CacheManager getCacheManager();
-
- /**
+ /**
+ *
+ * @return IndexManager
+ */
+ public IndexManager getIndexManager();
+
+ /**
+ *
+ * @return TransactionManager
+ */
+ public TransactionManager getTransactionManager();
+
+ /**
+ *
+ * @return CacheManager
+ */
+ public CacheManager getCacheManager();
+
+ /**
*
* @return Scheduler
*/
public Scheduler getScheduler();
-
- /**
+ /**
*
*/
- public void shutdown();
+ public void shutdown();
- /**
- *
- * @return Subject
- */
- public Subject getSubject();
+ /**
+ *
+ * @return Subject
+ */
+ public Subject getSubject();
- /**
- *
- * @param subject
- */
- public boolean setSubject(Subject subject);
-
- public DBBroker getBroker() throws EXistException; //TODO: remove 'throws EXistException'?
-
- public DBBroker authenticate(String username, Object credentials) throws AuthenticationException;
-
- /*
- * @Deprecated ?
- * try {
- * broker = database.authenticate(account, credentials);
- *
- * broker1 = database.get();
- * broker2 = database.get();
- * ...
- * brokerN = database.get();
- *
- * } finally {
- * database.release(broker);
- * }
- */
- public DBBroker get(Subject subject) throws EXistException;
- public DBBroker getActiveBroker(); //throws EXistException;
- public void release(DBBroker broker);
-
- /**
- * Returns the number of brokers currently serving requests for the database instance.
- *
- * @return The brokers count
- */
- public int countActiveBrokers();
-
- /**
- *
- * @return Debuggee
- */
- public Debuggee getDebuggee();
+ /**
+ *
+ * @param subject
+ */
+ public boolean setSubject(Subject subject);
- public PerformanceStats getPerformanceStats();
+ // TODO: remove 'throws EXistException'?
+ public DBBroker getBroker() throws EXistException;
- //old configuration
- public Configuration getConfiguration();
+ public DBBroker authenticate(String username, Object credentials) throws AuthenticationException;
- public NodeIdFactory getNodeFactory();
+ /*
+ * @Deprecated ?
+ *
+ * try {
+ * broker = database.authenticate(account, credentials);
+ *
+ * broker1 = database.get();
+ * broker2 = database.get();
+ * ...
+ * brokerN = database.get();
+ *
+ * } finally {
+ * database.release(broker);
+ * }
+ */
+ public DBBroker get(Subject subject) throws EXistException;
- public File getStoragePlace();
+ public DBBroker getActiveBroker(); // throws EXistException;
- public CollectionConfigurationManager getConfigurationManager();
+ public void release(DBBroker broker);
- /**
- * Master document triggers.
- */
- public Collection<DocumentTrigger> getDocumentTriggers();
+ /**
+ * Returns the number of brokers currently serving requests for the database
+ * instance.
+ *
+ * @return The brokers count
+ */
+ public int countActiveBrokers();
- public DocumentTrigger getDocumentTrigger();
+ /**
+ *
+ * @return Debuggee
+ */
+ public Debuggee getDebuggee();
- /**
- * Master Collection triggers.
- */
- public Collection<CollectionTrigger> getCollectionTriggers();
+ public PerformanceStats getPerformanceStats();
+
+ // old configuration
+ public Configuration getConfiguration();
+
+ public NodeIdFactory getNodeFactory();
+
+ public File getStoragePlace();
+
+ public CollectionConfigurationManager getConfigurationManager();
+
+ /**
+ * Master document triggers.
+ */
+ public Collection<TriggerProxy<? extends DocumentTrigger>> getDocumentTriggers();
+
+ // public DocumentTrigger getDocumentTrigger();
+
+ /**
+ * Master Collection triggers.
+ */
+ public Collection<TriggerProxy<? extends CollectionTrigger>> getCollectionTriggers();
+
+ // public CollectionTrigger getCollectionTrigger();
+
+ public void registerDocumentTrigger(Class<? extends DocumentTrigger> clazz);
+
+ public void registerCollectionTrigger(Class<? extends CollectionTrigger> clazz);
- public CollectionTrigger getCollectionTrigger();
+ public ProcessMonitor getProcessMonitor();
- public ProcessMonitor getProcessMonitor();
+ public boolean isReadOnly();
- public boolean isReadOnly();
+ public NotificationService getNotificationService();
- public NotificationService getNotificationService();
-
- public PluginsManager getPluginsManager();
+ public PluginsManager getPluginsManager();
- public SymbolTable getSymbols();
+ public SymbolTable getSymbols();
public MetaStorage getMetaStorage();
}
View
102 src/org/exist/collections/Collection.java
@@ -1096,18 +1096,14 @@ public void removeXMLResource(final Txn transaction, final DBBroker broker, fina
}
}
- DocumentTriggersVisitor triggersVisitor = null;
- if(useTriggers) {
- triggersVisitor = getConfiguration(broker).getDocumentTriggerProxies().instantiateVisitor(broker);
- triggersVisitor.beforeDeleteDocument(broker, transaction, doc);
- }
+ DocumentTriggers trigger = new DocumentTriggers(broker, null, this, useTriggers ? getConfiguration(broker) : null);
+
+ trigger.beforeDeleteDocument(broker, transaction, doc);
broker.removeXMLResource(transaction, doc);
documents.remove(docUri.getRawCollectionPath());
- if(useTriggers) {
- triggersVisitor.afterDeleteDocument(broker, transaction, getURI().append(docUri));
- }
+ trigger.afterDeleteDocument(broker, transaction, getURI().append(docUri));
broker.getBrokerPool().getNotificationService().notifyUpdate(doc, UpdateListener.REMOVE);
} finally {
@@ -1160,13 +1156,10 @@ public void removeBinaryResource(final Txn transaction, final DBBroker broker, f
}
doc.getUpdateLock().acquire(Lock.WRITE_LOCK);
-
- DocumentTriggersVisitor triggersVisitor = null;
- if(isTriggersEnabled()) {
- triggersVisitor = getConfiguration(broker).getDocumentTriggerProxies().instantiateVisitor(broker);
- triggersVisitor.beforeDeleteDocument(broker, transaction, doc);
- }
+ DocumentTriggers trigger = new DocumentTriggers(broker, null, this, isTriggersEnabled() ? getConfiguration(broker) : null);
+
+ trigger.beforeDeleteDocument(broker, transaction, doc);
try {
broker.removeBinaryResource(transaction, (BinaryDocument) doc);
@@ -1176,9 +1169,7 @@ public void removeBinaryResource(final Txn transaction, final DBBroker broker, f
documents.remove(doc.getFileURI().getRawCollectionPath());
- if(isTriggersEnabled()) {
- triggersVisitor.afterDeleteDocument(broker, transaction, doc.getURI());
- }
+ trigger.afterDeleteDocument(broker, transaction, doc.getURI());
} finally {
broker.getBrokerPool().getProcessMonitor().endJob();
@@ -1393,17 +1384,9 @@ private void storeXMLInternal(final Txn transaction, final DBBroker broker, fina
broker.deleteObservers();
if(info.isCreating()) {
- db.getDocumentTrigger().afterCreateDocument(broker, transaction, document);
+ info.getTriggers().afterCreateDocument(broker, transaction, document);
} else {
- db.getDocumentTrigger().afterUpdateDocument(broker, transaction, document);
- }
-
- if(isTriggersEnabled() && isCollectionConfigEnabled() && info.getTriggersVisitor() != null) {
- if(info.isCreating()) {
- info.getTriggersVisitor().afterCreateDocument(broker, transaction, document);
- } else {
- info.getTriggersVisitor().afterUpdateDocument(broker, transaction, document);
- }
+ info.getTriggers().afterUpdateDocument(broker, transaction, document);
}
db.getNotificationService().notifyUpdate(document, (info.isCreating() ? UpdateListener.ADD : UpdateListener.UPDATE));
@@ -1626,33 +1609,22 @@ private IndexInfo validateXMLResourceInternal(final Txn transaction, final DBBro
//confMgr.invalidateAll(getURI());
setCollectionConfigEnabled(false);
}
+
+ final DocumentTriggers trigger = new DocumentTriggers(broker, indexer, this, isTriggersEnabled() ? config : null);
+ trigger.setValidating(true);
+
+ info.setTriggers(trigger);
if(oldDoc == null) {
- db.getDocumentTrigger().beforeCreateDocument(broker, transaction, getURI().append(docUri));
+ trigger.beforeCreateDocument(broker, transaction, getURI().append(docUri));
} else {
- db.getDocumentTrigger().beforeUpdateDocument(broker, transaction, oldDoc);
+ trigger.beforeUpdateDocument(broker, transaction, oldDoc);
}
- DocumentTriggersVisitor triggersVisitor = null;
- if(isTriggersEnabled() && isCollectionConfigEnabled()) {
- triggersVisitor = getConfiguration(broker).getDocumentTriggerProxies().instantiateVisitor(broker);
-
- triggersVisitor.setOutputHandler(indexer);
- triggersVisitor.setLexicalOutputHandler(indexer);
- triggersVisitor.setValidating(true);
-
- if(oldDoc == null) {
- triggersVisitor.beforeCreateDocument(broker, transaction, getURI().append(docUri));
- } else {
- triggersVisitor.beforeUpdateDocument(broker, transaction, oldDoc);
- }
-
- info.setTriggersVisitor(triggersVisitor);
- }
-
if (LOG.isDebugEnabled()) {
LOG.debug("Scanning document " + getURI().append(docUri));
}
+
doValidate.run(info);
// new document is valid: remove old document
if (oldDoc != null) {
@@ -1697,10 +1669,9 @@ private IndexInfo validateXMLResourceInternal(final Txn transaction, final DBBro
document.setDocId(broker.getNextResourceId(transaction, this));
addDocument(transaction, broker, document);
}
- indexer.setValidating(false);
- if(triggersVisitor != null) {
- triggersVisitor.setValidating(false);
- }
+
+ trigger.setValidating(false);
+
return info;
} finally {
if (oldDoc != null && oldDocLocked) {
@@ -1892,20 +1863,15 @@ public BinaryDocument addBinaryResource(final Txn transaction, final DBBroker br
metadata.setLastModified(modified.getTime());
}
blob.setContentLength(size);
+
+ final DocumentTriggers trigger = new DocumentTriggers(broker, null, this, isTriggersEnabled() ? getConfiguration(broker) : null);
+
if (oldDoc == null) {
- db.getDocumentTrigger().beforeCreateDocument(broker, transaction, blob.getURI());
+ trigger.beforeCreateDocument(broker, transaction, blob.getURI());
} else {
- db.getDocumentTrigger().beforeUpdateDocument(broker, transaction, oldDoc);
- }
- DocumentTriggersVisitor triggersVisitor = null;
- if (isTriggersEnabled()) {
- triggersVisitor = getConfiguration(broker).getDocumentTriggerProxies().instantiateVisitor(broker);
- if (oldDoc == null) {
- triggersVisitor.beforeCreateDocument(broker, transaction, blob.getURI());
- } else {
- triggersVisitor.beforeUpdateDocument(broker, transaction, oldDoc);
- }
+ trigger.beforeUpdateDocument(broker, transaction, oldDoc);
}
+
if (oldDoc != null) {
LOG.debug("removing old document " + oldDoc.getFileURI());
if (oldDoc instanceof BinaryDocument) {
@@ -1917,19 +1883,13 @@ public BinaryDocument addBinaryResource(final Txn transaction, final DBBroker br
broker.storeBinaryResource(transaction, blob, is);
addDocument(transaction, broker, blob, oldDoc);
broker.storeXMLResource(transaction, blob);
+
if (oldDoc == null) {
- db.getDocumentTrigger().afterCreateDocument(broker, transaction, blob);
+ trigger.afterCreateDocument(broker, transaction, blob);
} else {
- db.getDocumentTrigger().afterUpdateDocument(broker, transaction, blob);
- }
- if (isTriggersEnabled()) {
- //Strange ! What is the "if" clause for ? -pb
- if (oldDoc == null) {
- triggersVisitor.afterCreateDocument(broker, transaction, blob);
- } else {
- triggersVisitor.afterUpdateDocument(broker, transaction, blob);
- }
+ trigger.afterUpdateDocument(broker, transaction, blob);
}
+
return blob;
} finally {
broker.getBrokerPool().getProcessMonitor().endJob();
View
76 src/org/exist/collections/CollectionConfiguration.java
@@ -1,6 +1,6 @@
/*
* eXist Open Source Native XML Database
- * Copyright (C) 2001-2012 The eXist Project
+ * Copyright (C) 2001-2014 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
@@ -16,19 +16,17 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * $Id$
*/
package org.exist.collections;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
-import org.exist.collections.triggers.AbstractTriggerProxy;
-import org.exist.collections.triggers.CollectionTriggerProxies;
+import org.exist.collections.triggers.CollectionTrigger;
import org.exist.collections.triggers.CollectionTriggerProxy;
-import org.exist.collections.triggers.DocumentTriggerProxies;
+import org.exist.collections.triggers.DocumentTrigger;
import org.exist.collections.triggers.DocumentTriggerProxy;
import org.exist.collections.triggers.Trigger;
import org.exist.collections.triggers.TriggerException;
@@ -80,8 +78,8 @@
private static final Logger LOG = Logger.getLogger(CollectionConfiguration.class);
- private DocumentTriggerProxies documentTriggerProxies = null;
- private CollectionTriggerProxies collectionTriggerProxies = null;
+ private List<TriggerProxy<? extends CollectionTrigger>> colTriggers = new ArrayList<TriggerProxy<? extends CollectionTrigger>>();
+ private List<TriggerProxy<? extends DocumentTrigger>> docTriggers = new ArrayList<TriggerProxy<? extends DocumentTrigger>>();
private IndexSpec indexSpec = null;
@@ -142,20 +140,8 @@ protected void read(DBBroker broker, Document doc, boolean checkOnly,
final NodeList triggers = node.getChildNodes();
for(int j = 0; j < triggers.getLength(); j++) {
node = triggers.item(j);
- if(node.getNodeType() == Node.ELEMENT_NODE &&
- node.getLocalName().equals(TRIGGER_ELEMENT)) {
- final List <TriggerProxy<? extends Trigger>> triggerProxys = configureTrigger(
- (Element)node, srcCollectionURI, checkOnly);
- if(triggerProxys != null) {
- for(final TriggerProxy<? extends Trigger> triggerProxy : triggerProxys) {
- if(triggerProxy instanceof DocumentTriggerProxy) {
- getDocumentTriggerProxies().add((DocumentTriggerProxy)triggerProxy);
- }
- if(triggerProxy instanceof CollectionTriggerProxy) {
- getCollectionTriggerProxies().add((CollectionTriggerProxy)triggerProxy);
- }
- }
- }
+ if(node.getNodeType() == Node.ELEMENT_NODE && node.getLocalName().equals(TRIGGER_ELEMENT)) {
+ configureTrigger((Element)node, srcCollectionURI, checkOnly);
}
}
} else if (INDEX_ELEMENT.equals(node.getLocalName())) {
@@ -302,22 +288,7 @@ public IndexSpec getIndexConfiguration() {
return indexSpec;
}
- public DocumentTriggerProxies getDocumentTriggerProxies() {
- if(documentTriggerProxies == null) {
- documentTriggerProxies = new DocumentTriggerProxies();
- }
- return documentTriggerProxies;
- }
-
- public CollectionTriggerProxies getCollectionTriggerProxies() {
- if(collectionTriggerProxies == null) {
- collectionTriggerProxies = new CollectionTriggerProxies();
- }
- return collectionTriggerProxies;
- }
-
- private List<TriggerProxy<? extends Trigger>> configureTrigger(Element triggerElement,
- XmldbURI collectionConfigurationURI, boolean testOnly) throws CollectionConfigurationException {
+ private void configureTrigger(Element triggerElement, XmldbURI collectionConfigurationURI, boolean testOnly) throws CollectionConfigurationException {
//TODO : rely on schema-driven validation -pb
@@ -327,12 +298,26 @@ public CollectionTriggerProxies getCollectionTriggerProxies() {
final Class clazz = Class.forName(classname);
if(!Trigger.class.isAssignableFrom(clazz)) {
throwOrLog("Trigger's class '" + classname + "' is not assignable from '" + Trigger.class + "'", testOnly);
- return null;
+ return;
}
final NodeList nlParameter = triggerElement.getElementsByTagNameNS(NAMESPACE, PARAMETER_ELEMENT);
final Map<String, List<? extends Object>> parameters = ParametersExtractor.extract(nlParameter);
- final List<TriggerProxy<? extends Trigger>> triggerProxys = AbstractTriggerProxy.newInstance(clazz, collectionConfigurationURI, parameters);
- return triggerProxys;
+
+ boolean added = false;
+ if(DocumentTrigger.class.isAssignableFrom(clazz)) {
+ docTriggers.add(new DocumentTriggerProxy((Class<? extends DocumentTrigger>)clazz, parameters)); //collectionConfigurationURI, parameters));
+ added = true;
+ }
+
+ if(CollectionTrigger.class.isAssignableFrom(clazz)) {
+ colTriggers.add(new CollectionTriggerProxy((Class<? extends CollectionTrigger>)clazz, parameters)); //collectionConfigurationURI, parameters));
+ added = true;
+ }
+
+ if(!added) {
+ throw new TriggerException("Unknown Trigger class type: " + clazz.getName());
+ }
+
} catch (final ClassNotFoundException e) {
if(testOnly) {
throw new CollectionConfigurationException(e.getMessage(), e);
@@ -346,7 +331,14 @@ public CollectionTriggerProxies getCollectionTriggerProxies() {
LOG.warn("Trigger class not found: " + te.getMessage(), te);
}
}
- return null;
+ }
+
+ public List<TriggerProxy<? extends CollectionTrigger>> collectionTriggers() {
+ return colTriggers;
+ }
+
+ public List<TriggerProxy<? extends DocumentTrigger>> documentTriggers() {
+ return docTriggers;
}
//TODO: code
View
30 src/org/exist/collections/IndexInfo.java
@@ -1,6 +1,6 @@
/*
* eXist Open Source Native XML Database
- * Copyright (C) 2000-2012 The eXist Project
+ * Copyright (C) 2000-2014 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
@@ -16,14 +16,12 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * $Id$
*/
package org.exist.collections;
import org.exist.Indexer;
import org.exist.Namespaces;
-import org.exist.collections.triggers.DocumentTriggersVisitor;
+import org.exist.collections.triggers.DocumentTriggers;
import org.exist.dom.DocumentImpl;
import org.exist.security.Permission;
import org.exist.storage.DBBroker;
@@ -48,7 +46,7 @@
private Indexer indexer;
private DOMStreamer streamer;
- private DocumentTriggersVisitor triggersVisitor;
+ private DocumentTriggers docTriggers;
private boolean creating = false;
private Permission oldDocPermissions = null;
private CollectionConfiguration collectionConfig;
@@ -62,12 +60,14 @@ public Indexer getIndexer() {
return indexer;
}
- public void setTriggersVisitor(DocumentTriggersVisitor triggersVisitor) {
- this.triggersVisitor = triggersVisitor;
+ //XXX: make protected
+ public void setTriggers(DocumentTriggers triggersVisitor) {
+ this.docTriggers = triggersVisitor;
}
- public DocumentTriggersVisitor getTriggersVisitor() {
- return triggersVisitor;
+ //XXX: make protected
+ public DocumentTriggers getTriggers() {
+ return docTriggers;
}
public void setCreating(boolean creating) {
@@ -90,10 +90,8 @@ void setReader(XMLReader reader, EntityResolver entityResolver) throws SAXExcept
if(entityResolver != null) {
reader.setEntityResolver(entityResolver);
}
- final LexicalHandler lexicalHandler = triggersVisitor == null ?
- indexer : triggersVisitor.getLexicalInputHandler();
- final ContentHandler contentHandler = triggersVisitor == null ?
- indexer : triggersVisitor.getInputHandler();
+ final LexicalHandler lexicalHandler = docTriggers == null ? indexer : docTriggers;
+ final ContentHandler contentHandler = docTriggers == null ? indexer : docTriggers;
reader.setProperty(Namespaces.SAX_LEXICAL_HANDLER, lexicalHandler);
reader.setContentHandler(contentHandler);
reader.setErrorHandler(indexer);
@@ -101,12 +99,12 @@ void setReader(XMLReader reader, EntityResolver entityResolver) throws SAXExcept
void setDOMStreamer(DOMStreamer streamer) {
this.streamer = streamer;
- if (triggersVisitor == null) {
+ if (docTriggers == null) {
streamer.setContentHandler(indexer);
streamer.setLexicalHandler(indexer);
} else {
- streamer.setContentHandler(triggersVisitor.getInputHandler());
- streamer.setLexicalHandler(triggersVisitor.getLexicalInputHandler());
+ streamer.setContentHandler(docTriggers);
+ streamer.setLexicalHandler(docTriggers);
}
}
View
56 src/org/exist/collections/triggers/AbstractTriggerProxies.java
@@ -1,56 +0,0 @@
-/*
- * eXist Open Source Native XML Database
- * Copyright (C) 2011-2012 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 library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * $Id$
- */
-package org.exist.collections.triggers;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.exist.storage.DBBroker;
-
-/**
- *
- * @author aretter
- */
-public abstract class AbstractTriggerProxies<T extends Trigger> implements TriggerProxies<T> {
-
- //extract signatures to interface
-
- private List<TriggerProxy<T>> proxies = new ArrayList<TriggerProxy<T>>();
-
- @Override
- public void add(TriggerProxy<T> proxy) {
- proxies.add(proxy);
- }
-
- protected List<T> instantiateTriggers(DBBroker broker) throws TriggerException {
-
- final List<T> triggers = new ArrayList<T>(proxies.size());
-
- for(final TriggerProxy<T> proxy : proxies) {
- triggers.add(proxy.newInstance(broker));
- }
-
- return triggers;
- }
-
- @Override
- public abstract TriggersVisitor<T> instantiateVisitor(DBBroker broker);
-}
View
68 src/org/exist/collections/triggers/AbstractTriggerProxy.java
@@ -1,6 +1,6 @@
/*
* eXist Open Source Native XML Database
- * Copyright (C) 2011-2012 The eXist Project
+ * Copyright (C) 2001-2014 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
@@ -16,19 +16,14 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * $Id$
*/
package org.exist.collections.triggers;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.exist.collections.Collection;
-import org.exist.security.PermissionDeniedException;
import org.exist.storage.DBBroker;
-import org.exist.xmldb.XmldbURI;
/**
*
@@ -36,33 +31,33 @@
*/
public abstract class AbstractTriggerProxy<T extends Trigger> implements TriggerProxy<T> {
- private final Class<T> clazz;
+ private final Class<? extends T> clazz;
private Map<String, List<? extends Object>> parameters;
- /**
- * The database Collection URI of where the configuration for this Trigger came from
- * typically somewhere under /db/system/config/db/
- */
- private final XmldbURI collectionConfigurationURI;
+// /**
+// * The database Collection URI of where the configuration for this Trigger came from
+// * typically somewhere under /db/system/config/db/
+// */
+// private final XmldbURI collectionConfigurationURI;
- public AbstractTriggerProxy(Class<? extends T> clazz, XmldbURI collectionConfigurationURI) {
- this.clazz = (Class<T>)clazz;
- this.collectionConfigurationURI = collectionConfigurationURI;
+ public AbstractTriggerProxy(Class<? extends T> clazz) {
+ this.clazz = clazz;
+// this.collectionConfigurationURI = collectionConfigurationURI;
}
- public AbstractTriggerProxy(Class<? extends T> clazz, XmldbURI collectionConfigurationURI, Map<String, List<? extends Object>> parameters) {
- this.clazz = (Class<T>)clazz;
- this.collectionConfigurationURI = collectionConfigurationURI;
+ public AbstractTriggerProxy(Class<? extends T> clazz, Map<String, List<? extends Object>> parameters) {
+ this.clazz = clazz;
+// this.collectionConfigurationURI = collectionConfigurationURI;
this.parameters = parameters;
}
- protected Class<T> getClazz() {
+ protected Class<? extends T> getClazz() {
return clazz;
}
- protected XmldbURI getCollectionConfigurationURI() {
- return collectionConfigurationURI;
- }
+// protected XmldbURI getCollectionConfigurationURI() {
+// return collectionConfigurationURI;
+// }
@Override
public void setParameters(Map<String, List<? extends Object>> parameters) {
@@ -73,16 +68,10 @@ public void setParameters(Map<String, List<? extends Object>> parameters) {
return parameters;
}
- public T newInstance(DBBroker broker) throws TriggerException {
+ public T newInstance(DBBroker broker, Collection collection) throws TriggerException {
try {
final T trigger = getClazz().newInstance();
- XmldbURI collectionForTrigger = getCollectionConfigurationURI();
- if(collectionForTrigger.startsWith(XmldbURI.CONFIG_COLLECTION_URI)) {
- collectionForTrigger = collectionForTrigger.trimFromBeginning(XmldbURI.CONFIG_COLLECTION_URI);
- }
-
- final Collection collection = broker.getCollection(collectionForTrigger);
trigger.configure(broker, collection, getParameters());
return trigger;
@@ -90,27 +79,6 @@ public T newInstance(DBBroker broker) throws TriggerException {
throw new TriggerException("Unable to instantiate Trigger '" + getClazz().getName() + "': " + ie.getMessage(), ie);
} catch (final IllegalAccessException iae) {
throw new TriggerException("Unable to instantiate Trigger '" + getClazz().getName() + "': " + iae.getMessage(), iae);
- } catch (final PermissionDeniedException pde) {
- throw new TriggerException("Unable to instantiate Trigger '" + getClazz().getName() + "': " + pde.getMessage(), pde);
- }
- }
-
- public static List<TriggerProxy<? extends Trigger>> newInstance(Class<? extends Trigger> c, XmldbURI collectionConfigurationURI, Map<String, List<? extends Object>> parameters) throws TriggerException {
-
- final List<TriggerProxy<? extends Trigger>> proxies = new ArrayList<TriggerProxy<? extends Trigger>>();
-
- if(DocumentTrigger.class.isAssignableFrom(c)) {
- proxies.add(new DocumentTriggerProxy((Class<? extends DocumentTrigger>)c, collectionConfigurationURI, parameters));
- }
-
- if(CollectionTrigger.class.isAssignableFrom(c)) {
- proxies.add(new CollectionTriggerProxy((Class<? extends CollectionTrigger>)c, collectionConfigurationURI, parameters));
- }
-
- if(proxies.isEmpty()) {
- throw new TriggerException("Unknown Trigger class type: " + c.getName());
}
-
- return proxies;
}
}
View
25 src/org/exist/collections/triggers/AbstractTriggersVisitor.java
@@ -1,6 +1,6 @@
/*
* eXist Open Source Native XML Database
- * Copyright (C) 2011-2012 The eXist Project
+ * Copyright (C) 2001-2014 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
@@ -16,12 +16,13 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * $Id$
*/
package org.exist.collections.triggers;
import java.util.List;
+import java.util.Map;
+
+import org.exist.collections.Collection;
import org.exist.storage.DBBroker;
/**
@@ -29,22 +30,18 @@
* @author aretter
*/
public abstract class AbstractTriggersVisitor<T extends Trigger> implements TriggersVisitor<T> {
- private final DBBroker broker;
- private final AbstractTriggerProxies<T> proxies;
+
private List<T> triggers;
- public AbstractTriggersVisitor(DBBroker broker, AbstractTriggerProxies<T> proxies) {
- this.broker = broker;
- this.proxies = proxies;
+ public AbstractTriggersVisitor(List<T> triggers) {
+ this.triggers = triggers;
+ }
+
+ @Override
+ public void configure(DBBroker broker, Collection parent, Map<String, List<? extends Object>> parameters) throws TriggerException {
}
- /**
- * lazy instantiated
- */
public List<T> getTriggers() throws TriggerException {
- if(triggers == null) {
- triggers = proxies.instantiateTriggers(broker);
- }
return triggers;
}
}
View
4 src/org/exist/collections/triggers/CollectionTrigger.java
@@ -1,6 +1,6 @@
/*
* eXist Open Source Native XML Database
- * Copyright (C) 2001-2012 The eXist Project
+ * Copyright (C) 2001-2014 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
@@ -16,8 +16,6 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * $Id$
*/
package org.exist.collections.triggers;
View
36 src/org/exist/collections/triggers/CollectionTriggerProxies.java
@@ -1,36 +0,0 @@
-/*
- * eXist Open Source Native XML Database
- * Copyright (C) 2011-2012 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 library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * $Id$
- */
-package org.exist.collections.triggers;
-
-import org.exist.storage.DBBroker;
-
-/**
- *
- * @author aretter
- */
-public class CollectionTriggerProxies extends AbstractTriggerProxies<CollectionTrigger> {
-
- @Override
- public CollectionTriggersVisitor instantiateVisitor(DBBroker broker) {
- return new CollectionTriggersVisitor(broker, this);
- }
-}
View
8 src/org/exist/collections/triggers/CollectionTriggerProxy.java
@@ -31,11 +31,11 @@
*/
public class CollectionTriggerProxy extends AbstractTriggerProxy<CollectionTrigger> {
- public CollectionTriggerProxy(Class<? extends CollectionTrigger> clazz, XmldbURI collectionConfigurationURI){
- super(clazz, collectionConfigurationURI);
+ public CollectionTriggerProxy(Class<? extends CollectionTrigger> clazz){
+ super(clazz);
}
- public CollectionTriggerProxy(Class<? extends CollectionTrigger> clazz, XmldbURI collectionConfigurationURI, Map<String, List<? extends Object>> parameters) {
- super(clazz, collectionConfigurationURI, parameters);
+ public CollectionTriggerProxy(Class<? extends CollectionTrigger> clazz, Map<String, List<? extends Object>> parameters) {
+ super(clazz, parameters);
}
}
View
155 src/org/exist/collections/triggers/CollectionTriggers.java
@@ -0,0 +1,155 @@
+/*
+ * eXist Open Source Native XML Database
+ * Copyright (C) 2001-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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package org.exist.collections.triggers;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.exist.collections.Collection;
+import org.exist.collections.CollectionConfiguration;
+import org.exist.storage.DBBroker;
+import org.exist.storage.txn.Txn;
+import org.exist.xmldb.XmldbURI;
+
+/**
+ * @author <a href="mailto:shabanovd@gmail.com">Dmitriy Shabanov</a>
+ *
+ */
+public class CollectionTriggers implements CollectionTrigger {
+
+ private final List<CollectionTrigger> triggers;
+
+ public CollectionTriggers(DBBroker broker) throws TriggerException {
+ this(broker, null, null);
+ }
+
+ public CollectionTriggers(DBBroker broker, Collection collection) throws TriggerException {
+ this(broker, collection, collection.getConfiguration(broker));
+ }
+
+ public CollectionTriggers(DBBroker broker, Collection collection, CollectionConfiguration config) throws TriggerException {
+
+ List<TriggerProxy<? extends CollectionTrigger>> colTriggers = null;
+ if (config != null) {
+ colTriggers = config.collectionTriggers();
+ }
+
+ java.util.Collection<TriggerProxy<? extends CollectionTrigger>> masterTriggers = broker.getDatabase().getCollectionTriggers();
+
+ triggers = new ArrayList<CollectionTrigger>( masterTriggers.size() + (colTriggers == null ? 0 : colTriggers.size()) );
+
+ for (TriggerProxy<? extends CollectionTrigger> colTrigger : masterTriggers) {
+
+ CollectionTrigger instance = colTrigger.newInstance(broker, collection);
+
+ register(instance);
+ }
+
+ if (colTriggers != null) {
+ for (TriggerProxy<? extends CollectionTrigger> colTrigger : colTriggers) {
+
+ CollectionTrigger instance = colTrigger.newInstance(broker, collection);
+
+ register(instance);
+ }
+ }
+ }
+
+ private void register(CollectionTrigger trigger) {
+ triggers.add(trigger);
+ }
+
+ @Override
+ public void configure(DBBroker broker, Collection col, Map<String, List<? extends Object>> parameters) throws TriggerException {
+ }
+
+ @Override
+ public void beforeCreateCollection(DBBroker broker, Txn txn, XmldbURI uri) throws TriggerException {
+ for (CollectionTrigger trigger : triggers) {
+ trigger.beforeCreateCollection(broker, txn, uri);
+ }
+ }
+
+ @Override
+ public void afterCreateCollection(DBBroker broker, Txn txn, Collection collection) {
+ for (CollectionTrigger trigger : triggers) {
+ try {
+ trigger.afterCreateCollection(broker, txn, collection);
+ } catch (Exception e) {
+ Trigger.LOG.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ @Override
+ public void beforeCopyCollection(DBBroker broker, Txn txn, Collection collection, XmldbURI newUri) throws TriggerException {
+ for (CollectionTrigger trigger : triggers) {
+ trigger.beforeCopyCollection(broker, txn, collection, newUri);
+ }
+ }
+
+ @Override
+ public void afterCopyCollection(DBBroker broker, Txn txn, Collection collection, XmldbURI oldUri) {
+ for (CollectionTrigger trigger : triggers) {
+ try {
+ trigger.afterCopyCollection(broker, txn, collection, oldUri);
+ } catch (Exception e) {
+ Trigger.LOG.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ @Override
+ public void beforeMoveCollection(DBBroker broker, Txn txn, Collection collection, XmldbURI newUri) throws TriggerException {
+ for (CollectionTrigger trigger : triggers) {
+ trigger.beforeMoveCollection(broker, txn, collection, newUri);
+ }
+ }
+
+ @Override
+ public void afterMoveCollection(DBBroker broker, Txn txn, Collection collection, XmldbURI oldUri) {
+ for (CollectionTrigger trigger : triggers) {
+ try {
+ trigger.afterMoveCollection(broker, txn, collection, oldUri);
+ } catch (Exception e) {
+ Trigger.LOG.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ @Override
+ public void beforeDeleteCollection(DBBroker broker, Txn txn, Collection collection) throws TriggerException {
+ for (CollectionTrigger trigger : triggers) {
+ trigger.beforeDeleteCollection(broker, txn, collection);
+ }
+ }
+
+ @Override
+ public void afterDeleteCollection(DBBroker broker, Txn txn, XmldbURI uri) {
+ for (CollectionTrigger trigger : triggers) {
+ try {
+ trigger.afterDeleteCollection(broker, txn, uri);
+ } catch (Exception e) {
+ Trigger.LOG.error(e.getMessage(), e);
+ }
+ }
+ }
+}
View
76 src/org/exist/collections/triggers/CollectionTriggersVisitor.java
@@ -1,6 +1,6 @@
/*
* eXist Open Source Native XML Database
- * Copyright (C) 2011-2012 The eXist Project
+ * Copyright (C) 2001-2014 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
@@ -16,89 +16,21 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * $Id$
*/
package org.exist.collections.triggers;
import java.util.List;
-import java.util.Map;
import org.apache.log4j.Logger;
-import org.exist.collections.Collection;
-import org.exist.storage.DBBroker;
-import org.exist.storage.txn.Txn;
-import org.exist.xmldb.XmldbURI;