use of org.exist.collections.triggers.TriggerException in project exist by eXist-db.
the class RESTServer method doPut.
/**
* Handles PUT requests. The request content is stored as a new resource at
* the specified location. If the resource already exists, it is overwritten
* if the user has write permissions.
*
* The resource type depends on the content type specified in the HTTP
* header. The content type will be looked up in the global mime table. If
* the corresponding mime type is not a know XML mime type, the resource
* will be stored as a binary resource.
*
* @param broker the database broker
* @param transaction the database transaction
* @param request the request
* @param response the response
* @param path the path of the request
*
* @throws BadRequestException if a bad request is made
* @throws PermissionDeniedException if the request has insufficient permissions
* @throws NotFoundException if the request resource cannot be found
* @throws IOException if an I/O error occurs
*/
public void doPut(final DBBroker broker, final Txn transaction, final XmldbURI path, final HttpServletRequest request, final HttpServletResponse response) throws BadRequestException, PermissionDeniedException, IOException, NotFoundException {
if (checkForXQueryTarget(broker, transaction, path, request, response)) {
return;
}
// fourth, process the request
final XmldbURI docUri = path.lastSegment();
final XmldbURI collUri = path.removeLastSegment();
if (docUri == null || collUri == null) {
throw new BadRequestException("Bad path: " + path);
}
// TODO : use getOrCreateCollection() right now ?
try (final ManagedCollectionLock managedCollectionLock = broker.getBrokerPool().getLockManager().acquireCollectionWriteLock(collUri)) {
final Collection collection = broker.getOrCreateCollection(transaction, collUri);
final MimeType mime;
String contentType = request.getContentType();
if (contentType != null) {
final int semicolon = contentType.indexOf(';');
if (semicolon > 0) {
contentType = contentType.substring(0, semicolon).trim();
}
mime = MimeTable.getInstance().getContentType(contentType);
} else {
mime = MimeTable.getInstance().getContentTypeFor(docUri);
}
// TODO(AR) in storeDocument, if the input source has an InputStream (but is not a subclass: FileInputSource or ByteArrayInputSource), need to handle caching and reusing the input stream between validate and store
try (final FilterInputStreamCache cache = FilterInputStreamCacheFactory.getCacheInstance(() -> (String) broker.getConfiguration().getProperty(Configuration.BINARY_CACHE_CLASS_PROPERTY), request.getInputStream());
final CachingFilterInputStream cfis = new CachingFilterInputStream(cache)) {
broker.storeDocument(transaction, docUri, new CachingFilterInputStreamInputSource(cfis), mime, collection);
}
response.setStatus(HttpServletResponse.SC_CREATED);
// try(final FilterInputStreamCache cache = FilterInputStreamCacheFactory.getCacheInstance(() -> (String) broker.getConfiguration().getProperty(Configuration.BINARY_CACHE_CLASS_PROPERTY), request.getInputStream());
// final InputStream cfis = new CachingFilterInputStream(cache)) {
//
// if (mime.isXMLType()) {
// cfis.mark(Integer.MAX_VALUE);
// final IndexInfo info = collection.validateXMLResource(transaction, broker, docUri, new InputSource(cfis));
// info.getDocument().setMimeType(contentType);
// cfis.reset();
// collection.store(transaction, broker, info, new InputSource(cfis));
// response.setStatus(HttpServletResponse.SC_CREATED);
// } else {
// collection.addBinaryResource(transaction, broker, docUri, cfis, contentType, request.getContentLength());
// response.setStatus(HttpServletResponse.SC_CREATED);
// }
// }
} catch (final SAXParseException e) {
throw new BadRequestException("Parsing exception at " + e.getLineNumber() + "/" + e.getColumnNumber() + ": " + e.toString());
} catch (final TriggerException | LockException e) {
throw new PermissionDeniedException(e.getMessage());
} catch (final SAXException e) {
Exception o = e.getException();
if (o == null) {
o = e;
}
throw new BadRequestException("Parsing exception: " + o.getMessage());
} catch (final EXistException e) {
throw new BadRequestException("Internal error: " + e.getMessage());
}
}
use of org.exist.collections.triggers.TriggerException in project exist by eXist-db.
the class RESTServer method doDelete.
public void doDelete(final DBBroker broker, final Txn transaction, final String path, final HttpServletRequest request, final HttpServletResponse response) throws PermissionDeniedException, NotFoundException, IOException, BadRequestException {
final XmldbURI pathURI = XmldbURI.createInternal(path);
if (checkForXQueryTarget(broker, transaction, pathURI, request, response)) {
return;
}
try {
try (final Collection collection = broker.openCollection(pathURI, LockMode.WRITE_LOCK)) {
if (collection != null) {
// remove the collection
LOG.debug("removing collection {}", path);
broker.removeCollection(transaction, collection);
response.setStatus(HttpServletResponse.SC_OK);
} else {
try (final LockedDocument lockedDocument = broker.getXMLResource(pathURI, LockMode.WRITE_LOCK)) {
final DocumentImpl doc = lockedDocument == null ? null : lockedDocument.getDocument();
if (doc == null) {
throw new NotFoundException("No document or collection found for path: " + path);
} else {
if (!doc.getPermissions().validate(broker.getCurrentSubject(), Permission.WRITE)) {
throw new PermissionDeniedException("Account '" + broker.getCurrentSubject().getName() + "' not allowed requested access to document '" + pathURI + "'");
}
// remove the document
if (LOG.isDebugEnabled()) {
LOG.debug("removing document {}", path);
}
if (doc.getResourceType() == DocumentImpl.BINARY_FILE) {
doc.getCollection().removeBinaryResource(transaction, broker, pathURI.lastSegment());
} else {
doc.getCollection().removeXMLResource(transaction, broker, pathURI.lastSegment());
}
response.setStatus(HttpServletResponse.SC_OK);
}
}
}
}
} catch (final TriggerException e) {
throw new PermissionDeniedException("Trigger failed: " + e.getMessage());
} catch (final LockException e) {
throw new PermissionDeniedException("Could not acquire lock: " + e.getMessage());
}
}
use of org.exist.collections.triggers.TriggerException 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.collections.triggers.TriggerException 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;
}
use of org.exist.collections.triggers.TriggerException in project exist by eXist-db.
the class Rename method eval.
@Override
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 Rename 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 rename 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()) {
QName newQName;
final Item item = contentSeq.itemAt(0);
if (item.getType() == Type.QNAME) {
newQName = ((QNameValue) item).getQName();
} else {
try {
newQName = QName.parse(context, item.getStringValue());
} catch (final QName.IllegalQNameException iqe) {
throw new XPathException(this, ErrorCodes.XPST0081, "No namespace defined for prefix " + item.getStringValue());
}
}
// start a transaction
try (final Txn transaction = getTransaction()) {
final StoredNode[] ql = selectAndLock(transaction, inSeq);
final NotificationService notifier = context.getBroker().getBrokerPool().getNotificationService();
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() + "'!");
}
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 XPathException(this, "unsupported node-type");
}
newNode.setNodeName(newQName, context.getBroker().getBrokerPool().getSymbols());
parent.updateChild(transaction, node, newNode);
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 PermissionDeniedException | EXistException | 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;
}
Aggregations