use of org.exist.storage.NotificationService in project exist by eXist-db.
the class Update method eval.
/* (non-Javadoc)
* @see org.exist.xquery.AbstractExpression#eval(org.exist.xquery.value.Sequence, org.exist.xquery.value.Item)
*/
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
if (contextItem != null) {
contextSequence = contextItem.toSequence();
}
final Sequence contentSeq = value.eval(contextSequence);
if (contentSeq.isEmpty()) {
throw new XPathException(this, Messages.getMessage(Error.UPDATE_EMPTY_CONTENT));
}
final Sequence inSeq = select.eval(contextSequence);
/* If we try and Update a node at an invalid location,
* trap the error in a context variable,
* this is then accessible from xquery via. the context extension module - deliriumsky
* TODO: This trapping could be expanded further - basically where XPathException is thrown from thiss class
* TODO: Maybe we could provide more detailed messages in the trap, e.g. couldnt update node `xyz` into `abc` becuase... this would be nicer for the end user of the xquery application
*/
if (!Type.subTypeOf(inSeq.getItemType(), Type.NODE)) {
// Indicate the failure to perform this update by adding it to the sequence in the context variable XQueryContext.XQUERY_CONTEXTVAR_XQUERY_UPDATE_ERROR
ValueSequence prevUpdateErrors = null;
final XPathException xpe = new XPathException(this, Messages.getMessage(Error.UPDATE_SELECT_TYPE));
final Object ctxVarObj = context.getAttribute(XQueryContext.XQUERY_CONTEXTVAR_XQUERY_UPDATE_ERROR);
if (ctxVarObj == null) {
prevUpdateErrors = new ValueSequence();
} else {
prevUpdateErrors = (ValueSequence) XPathUtil.javaObjectToXPath(ctxVarObj, context);
}
prevUpdateErrors.add(new StringValue(xpe.getMessage()));
context.setAttribute(XQueryContext.XQUERY_CONTEXTVAR_XQUERY_UPDATE_ERROR, prevUpdateErrors);
if (!inSeq.isEmpty()) {
// TODO: should we trap this instead of throwing an exception - deliriumsky?
throw xpe;
}
}
if (!inSeq.isEmpty()) {
context.pushInScopeNamespaces();
// start a transaction
try (final Txn transaction = getTransaction()) {
final NotificationService notifier = context.getBroker().getBrokerPool().getNotificationService();
final StoredNode[] ql = selectAndLock(transaction, inSeq);
for (final StoredNode node : ql) {
final DocumentImpl doc = node.getOwnerDocument();
if (!doc.getPermissions().validate(context.getSubject(), Permission.WRITE)) {
throw new XPathException(this, "User '" + context.getSubject().getName() + "' does not have permission to write to the document '" + doc.getDocumentURI() + "'!");
}
// update the document
switch(node.getNodeType()) {
case Node.ELEMENT_NODE:
final NodeListImpl content = new NodeListImpl();
for (final SequenceIterator j = contentSeq.iterate(); j.hasNext(); ) {
final Item next = j.nextItem();
if (Type.subTypeOf(next.getType(), Type.NODE)) {
content.add(((NodeValue) next).getNode());
} else {
final TextImpl text = new TextImpl(next.getStringValue());
content.add(text);
}
}
((ElementImpl) node).update(transaction, content);
break;
case Node.TEXT_NODE:
final ElementImpl textParent = (ElementImpl) node.getParentNode();
final TextImpl text = new TextImpl(contentSeq.getStringValue());
text.setOwnerDocument(doc);
textParent.updateChild(transaction, node, text);
break;
case Node.ATTRIBUTE_NODE:
final ElementImpl attrParent = (ElementImpl) ((Attr) node).getOwnerElement();
if (attrParent == null) {
LOG.warn("parent node not found for {}", node.getNodeId());
break;
}
final AttrImpl attr = (AttrImpl) node;
final AttrImpl attribute = new AttrImpl(attr.getQName(), contentSeq.getStringValue(), context.getBroker().getBrokerPool().getSymbols());
attribute.setOwnerDocument(doc);
attrParent.updateChild(transaction, node, attribute);
break;
default:
throw new XPathException(this, "unsupported node-type");
}
doc.setLastModified(System.currentTimeMillis());
modifiedDocuments.add(doc);
context.getBroker().storeXMLResource(transaction, doc);
notifier.notifyUpdate(doc, UpdateListener.UPDATE);
}
finishTriggers(transaction);
// commit the transaction
transaction.commit();
} catch (final LockException | EXistException | TriggerException e) {
throw new XPathException(this, e.getMessage(), e);
} finally {
unlockDocuments();
context.popInScopeNamespaces();
}
}
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", Sequence.EMPTY_SEQUENCE);
}
return Sequence.EMPTY_SEQUENCE;
}
use of org.exist.storage.NotificationService in project exist by eXist-db.
the class Replace method process.
@Override
public long process(Txn transaction) throws PermissionDeniedException, LockException, EXistException, XPathException, TriggerException {
final NodeList children = content;
if (children.getLength() == 0) {
return 0;
}
if (children.getLength() > 1) {
throw new EXistException("xupdate:replace requires exactly one content node");
}
LOG.debug("processing replace ...");
int modifications = children.getLength();
try {
final StoredNode[] ql = selectAndLock(transaction);
final NotificationService notifier = broker.getBrokerPool().getNotificationService();
Node temp;
TextImpl text;
AttrImpl attribute;
ElementImpl parent;
for (final StoredNode node : ql) {
if (node == null) {
LOG.warn("select {} returned empty node set", selectStmt);
continue;
}
final DocumentImpl doc = node.getOwnerDocument();
if (!doc.getPermissions().validate(broker.getCurrentSubject(), Permission.WRITE)) {
throw new PermissionDeniedException("User '" + broker.getCurrentSubject().getName() + "' does not have permission to write to the document '" + doc.getDocumentURI() + "'!");
}
parent = (ElementImpl) node.getParentStoredNode();
if (parent == null) {
throw new EXistException("The root element of a document can not be replaced with 'xu:replace'. " + "Please consider removing the document or use 'xu:update' to just replace the children of the root.");
}
switch(node.getNodeType()) {
case Node.ELEMENT_NODE:
if (modifications == 0) {
modifications = 1;
}
temp = children.item(0);
parent.replaceChild(transaction, temp, node);
break;
case Node.TEXT_NODE:
temp = children.item(0);
text = new TextImpl(temp.getNodeValue());
modifications = 1;
text.setOwnerDocument(doc);
parent.updateChild(transaction, node, text);
break;
case Node.ATTRIBUTE_NODE:
final AttrImpl attr = (AttrImpl) node;
temp = children.item(0);
attribute = new AttrImpl(attr.getQName(), temp.getNodeValue(), broker.getBrokerPool().getSymbols());
attribute.setOwnerDocument(doc);
parent.updateChild(transaction, node, attribute);
break;
default:
throw new EXistException("unsupported node-type");
}
doc.setLastModified(System.currentTimeMillis());
modifiedDocuments.add(doc);
broker.storeXMLResource(transaction, doc);
notifier.notifyUpdate(doc, UpdateListener.UPDATE);
}
checkFragmentation(transaction, modifiedDocuments);
} finally {
unlockDocuments(transaction);
}
return modifications;
}
use of org.exist.storage.NotificationService in project exist by eXist-db.
the class Rename method process.
@Override
public long process(Txn transaction) throws PermissionDeniedException, LockException, EXistException, XPathException, TriggerException {
final NodeList children = content;
if (children.getLength() == 0) {
return 0;
}
int modificationCount = 0;
try {
final StoredNode[] ql = selectAndLock(transaction);
final NotificationService notifier = broker.getBrokerPool().getNotificationService();
final String newName = children.item(0).getTextContent();
for (final StoredNode node : ql) {
final DocumentImpl doc = node.getOwnerDocument();
if (!doc.getPermissions().validate(broker.getCurrentSubject(), Permission.WRITE)) {
throw new PermissionDeniedException("User '" + broker.getCurrentSubject().getName() + "' does not have permission to write to the document '" + doc.getDocumentURI() + "'!");
}
final NodeImpl parent = (NodeImpl) getParent(node);
// update the document
final NamedNode newNode;
switch(node.getNodeType()) {
case Node.ELEMENT_NODE:
newNode = new ElementImpl((ElementImpl) node);
break;
case Node.ATTRIBUTE_NODE:
newNode = new AttrImpl((AttrImpl) node);
break;
default:
throw new EXistException("unsupported node-type");
}
newNode.setNodeName(new QName(newName, "", null));
parent.updateChild(transaction, node, newNode);
modificationCount++;
doc.setLastModified(System.currentTimeMillis());
modifiedDocuments.add(doc);
broker.storeXMLResource(transaction, doc);
notifier.notifyUpdate(doc, UpdateListener.UPDATE);
}
checkFragmentation(transaction, modifiedDocuments);
} finally {
unlockDocuments(transaction);
}
return modificationCount;
}
use of org.exist.storage.NotificationService in project exist by eXist-db.
the class Delete method eval.
/* (non-Javadoc)
* @see org.exist.xquery.AbstractExpression#eval(org.exist.xquery.value.Sequence, org.exist.xquery.value.Item)
*/
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
if (contextItem != null) {
contextSequence = contextItem.toSequence();
}
final Sequence inSeq = select.eval(contextSequence);
/* If we try and Delete a node at an invalid location,
* trap the error in a context variable,
* this is then accessible from xquery via. the context extension module - deliriumsky
* TODO: This trapping could be expanded further - basically where XPathException is thrown from thiss class
* TODO: Maybe we could provide more detailed messages in the trap, e.g. couldnt delete node `xyz` into `abc` becuase... this would be nicer for the end user of the xquery application
*/
if (!Type.subTypeOf(inSeq.getItemType(), Type.NODE)) {
// Indicate the failure to perform this update by adding it to the sequence in the context variable XQueryContext.XQUERY_CONTEXTVAR_XQUERY_UPDATE_ERROR
ValueSequence prevUpdateErrors = null;
final XPathException xpe = new XPathException(this, Messages.getMessage(Error.UPDATE_SELECT_TYPE));
final Object ctxVarObj = context.getAttribute(XQueryContext.XQUERY_CONTEXTVAR_XQUERY_UPDATE_ERROR);
if (ctxVarObj == null) {
prevUpdateErrors = new ValueSequence();
} else {
prevUpdateErrors = (ValueSequence) XPathUtil.javaObjectToXPath(ctxVarObj, context);
}
prevUpdateErrors.add(new StringValue(xpe.getMessage()));
context.setAttribute(XQueryContext.XQUERY_CONTEXTVAR_XQUERY_UPDATE_ERROR, prevUpdateErrors);
if (!inSeq.isEmpty()) {
// TODO: should we trap this instead of throwing an exception - deliriumsky?
throw xpe;
}
}
if (!inSeq.isEmpty()) {
// start a transaction
try (final Txn transaction = getTransaction()) {
final NotificationService notifier = context.getBroker().getBrokerPool().getNotificationService();
final StoredNode[] ql = selectAndLock(transaction, inSeq);
for (final StoredNode node : ql) {
final DocumentImpl doc = node.getOwnerDocument();
if (!doc.getPermissions().validate(context.getSubject(), Permission.WRITE)) {
// transact.abort(transaction);
throw new PermissionDeniedException("User '" + context.getSubject().getName() + "' does not have permission to write to the document '" + doc.getDocumentURI() + "'!");
}
// update the document
final NodeImpl parent = (NodeImpl) getParent(node);
if (parent == null) {
LOG.debug("Cannot remove the document element (no parent node)");
throw new XPathException(this, "It is not possible to remove the document element.");
} else if (parent.getNodeType() != Node.ELEMENT_NODE) {
if (LOG.isDebugEnabled()) {
LOG.debug("parent = {}; {}", parent.getNodeType(), parent.getNodeName());
}
// transact.abort(transaction);
throw new XPathException(this, "you cannot remove the document element. Use update " + "instead");
} else {
parent.removeChild(transaction, node);
}
doc.setLastModified(System.currentTimeMillis());
modifiedDocuments.add(doc);
context.getBroker().storeXMLResource(transaction, doc);
notifier.notifyUpdate(doc, UpdateListener.UPDATE);
}
finishTriggers(transaction);
// commit the transaction
transaction.commit();
} catch (final EXistException | PermissionDeniedException | LockException | TriggerException e) {
throw new XPathException(this, e.getMessage(), e);
} finally {
unlockDocuments();
}
}
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", Sequence.EMPTY_SEQUENCE);
}
return Sequence.EMPTY_SEQUENCE;
}
use of org.exist.storage.NotificationService in project exist by eXist-db.
the class Replace method eval.
/* (non-Javadoc)
* @see org.exist.xquery.AbstractExpression#eval(org.exist.xquery.value.Sequence, org.exist.xquery.value.Item)
*/
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
if (contextItem != null) {
contextSequence = contextItem.toSequence();
}
final Sequence inSeq = select.eval(contextSequence);
if (inSeq.isEmpty()) {
return Sequence.EMPTY_SEQUENCE;
}
/* If we try and Replace a node at an invalid location,
* trap the error in a context variable,
* this is then accessible from xquery via. the context extension module - deliriumsky
* TODO: This trapping could be expanded further - basically where XPathException is thrown from thiss class
* TODO: Maybe we could provide more detailed messages in the trap, e.g. couldnt replace node `xyz` into `abc` becuase... this would be nicer for the end user of the xquery application
*/
if (!Type.subTypeOf(inSeq.getItemType(), Type.NODE)) {
// Indicate the failure to perform this update by adding it to the sequence in the context variable XQueryContext.XQUERY_CONTEXTVAR_XQUERY_UPDATE_ERROR
ValueSequence prevUpdateErrors = null;
final XPathException xpe = new XPathException(this, Messages.getMessage(Error.UPDATE_SELECT_TYPE));
final Object ctxVarObj = context.getAttribute(XQueryContext.XQUERY_CONTEXTVAR_XQUERY_UPDATE_ERROR);
if (ctxVarObj == null) {
prevUpdateErrors = new ValueSequence();
} else {
prevUpdateErrors = (ValueSequence) XPathUtil.javaObjectToXPath(ctxVarObj, context);
}
prevUpdateErrors.add(new StringValue(xpe.getMessage()));
context.setAttribute(XQueryContext.XQUERY_CONTEXTVAR_XQUERY_UPDATE_ERROR, prevUpdateErrors);
if (!inSeq.isEmpty()) {
// TODO: should we trap this instead of throwing an exception - deliriumsky?
throw xpe;
}
}
// END trap Replace failure
Sequence contentSeq = value.eval(contextSequence);
if (contentSeq.isEmpty()) {
throw new XPathException(this, Messages.getMessage(Error.UPDATE_EMPTY_CONTENT));
}
context.pushInScopeNamespaces();
contentSeq = deepCopy(contentSeq);
// start a transaction
try (final Txn transaction = getTransaction()) {
final StoredNode[] ql = selectAndLock(transaction, inSeq);
final NotificationService notifier = context.getBroker().getBrokerPool().getNotificationService();
Item temp;
TextImpl text;
AttrImpl attribute;
ElementImpl parent;
for (final StoredNode node : ql) {
final DocumentImpl doc = node.getOwnerDocument();
if (!doc.getPermissions().validate(context.getSubject(), Permission.WRITE)) {
throw new PermissionDeniedException("User '" + context.getSubject().getName() + "' does not have permission to write to the document '" + doc.getDocumentURI() + "'!");
}
// update the document
parent = (ElementImpl) node.getParentStoredNode();
if (parent == null) {
throw new XPathException(this, "The root element of a document can not be replaced with 'update replace'. " + "Please consider removing the document or use 'update value' to just replace the children of the root.");
}
switch(node.getNodeType()) {
case Node.ELEMENT_NODE:
temp = contentSeq.itemAt(0);
if (!Type.subTypeOf(temp.getType(), Type.NODE)) {
throw new XPathException(this, Messages.getMessage(Error.UPDATE_REPLACE_ELEM_TYPE, Type.getTypeName(temp.getType())));
}
parent.replaceChild(transaction, ((NodeValue) temp).getNode(), node);
break;
case Node.TEXT_NODE:
text = new TextImpl(contentSeq.getStringValue());
text.setOwnerDocument(doc);
parent.updateChild(transaction, node, text);
break;
case Node.ATTRIBUTE_NODE:
final AttrImpl attr = (AttrImpl) node;
attribute = new AttrImpl(attr.getQName(), contentSeq.getStringValue(), context.getBroker().getBrokerPool().getSymbols());
attribute.setOwnerDocument(doc);
parent.updateChild(transaction, node, attribute);
break;
default:
throw new EXistException("unsupported node-type");
}
doc.setLastModified(System.currentTimeMillis());
modifiedDocuments.add(doc);
context.getBroker().storeXMLResource(transaction, doc);
notifier.notifyUpdate(doc, UpdateListener.UPDATE);
}
finishTriggers(transaction);
// commit the transaction
transaction.commit();
} catch (final LockException | PermissionDeniedException | EXistException | TriggerException e) {
throw new XPathException(this, e.getMessage(), e);
} finally {
unlockDocuments();
context.popInScopeNamespaces();
}
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", Sequence.EMPTY_SEQUENCE);
}
return Sequence.EMPTY_SEQUENCE;
}
Aggregations