Search in sources :

Example 36 with XmldbURI

use of org.exist.xmldb.XmldbURI in project exist by eXist-db.

the class Deployment method deploy.

public Optional<String> deploy(final DBBroker broker, final Txn transaction, final String pkgName, final Optional<ExistRepository> repo, final String userTarget) throws PackageException, IOException {
    final Optional<Path> maybePackageDir = getPackageDir(pkgName, repo);
    if (!maybePackageDir.isPresent()) {
        throw new PackageException("Package not found: " + pkgName);
    }
    final Path packageDir = maybePackageDir.get();
    final DocumentImpl repoXML = getRepoXML(broker, packageDir);
    if (repoXML == null) {
        return Optional.empty();
    }
    try {
        // if there's a <setup> element, run the query it points to
        final Optional<ElementImpl> setup = findElement(repoXML, SETUP_ELEMENT);
        final Optional<String> setupPath = setup.map(ElementImpl::getStringValue).filter(s -> !s.isEmpty());
        if (setupPath.isPresent()) {
            runQuery(broker, null, packageDir, setupPath.get(), pkgName, QueryPurpose.SETUP);
            return Optional.empty();
        } else {
            // otherwise create the target collection
            XmldbURI targetCollection = null;
            if (userTarget != null) {
                try {
                    targetCollection = XmldbURI.create(userTarget);
                } catch (final IllegalArgumentException e) {
                    throw new PackageException("Bad collection URI: " + userTarget, e);
                }
            } else {
                final Optional<ElementImpl> target = findElement(repoXML, TARGET_COLL_ELEMENT);
                final Optional<String> targetPath = target.map(ElementImpl::getStringValue).filter(s -> !s.isEmpty());
                if (targetPath.isPresent()) {
                    // determine target collection
                    try {
                        targetCollection = XmldbURI.create(getTargetCollection(broker, targetPath.get()));
                    } catch (final IllegalArgumentException e) {
                        throw new PackageException("Bad collection URI for <target> element: " + targetPath.get(), e);
                    }
                } else {
                    LOG.warn("EXPath Package '{}' does not contain a <target> in its repo.xml, no files will be deployed to /apps", pkgName);
                }
            }
            if (targetCollection == null) {
                // no target means: package does not need to be deployed into database
                // however, we need to preserve a copy for backup purposes
                final Optional<Package> pkg = getPackage(pkgName, repo);
                pkg.orElseThrow(() -> new XPathException("expath repository is not available so the package was not stored."));
                final String pkgColl = pkg.get().getAbbrev() + "-" + pkg.get().getVersion();
                targetCollection = XmldbURI.SYSTEM.append("repo/" + pkgColl);
            }
            // extract the permissions (if any)
            final Optional<ElementImpl> permissions = findElement(repoXML, PERMISSIONS_ELEMENT);
            final Optional<RequestedPerms> requestedPerms = permissions.flatMap(elem -> {
                final Optional<Either<Integer, String>> perms = Optional.ofNullable(elem.getAttribute("mode")).flatMap(mode -> {
                    try {
                        return Optional.of(Either.Left(Integer.parseInt(mode, 8)));
                    } catch (final NumberFormatException e) {
                        if (mode.matches("^[rwx-]{9}")) {
                            return Optional.of(Either.Right(mode));
                        } else {
                            return Optional.empty();
                        }
                    }
                });
                return perms.map(p -> new RequestedPerms(elem.getAttribute("user"), elem.getAttribute("password"), Optional.ofNullable(elem.getAttribute("group")), p));
            });
            // check that if there were permissions then we were able to parse them, a failure would be related to the mode string
            if (permissions.isPresent() && !requestedPerms.isPresent()) {
                final String mode = permissions.map(elem -> elem.getAttribute("mode")).orElse(null);
                throw new PackageException("Bad format for mode attribute in <permissions>: " + mode);
            }
            // run the pre-setup query if present
            final Optional<ElementImpl> preSetup = findElement(repoXML, PRE_SETUP_ELEMENT);
            final Optional<String> preSetupPath = preSetup.map(ElementImpl::getStringValue).filter(s -> !s.isEmpty());
            if (preSetupPath.isPresent()) {
                runQuery(broker, targetCollection, packageDir, preSetupPath.get(), pkgName, QueryPurpose.PREINSTALL);
            }
            // TODO: if the user already exists, check and ensure the user is assigned to the specified group
            if (requestedPerms.isPresent()) {
                checkUserSettings(broker, requestedPerms.get());
            }
            final InMemoryNodeSet resources = findElements(repoXML, RESOURCES_ELEMENT);
            // store all package contents into database, using the user/group/mode in the permissions element. however:
            // 1. repo.xml is excluded for now, since it may contain the default user's password in the clear
            // 2. contents of directories identified in the path attribute of any <resource path=""/> element are stored as binary
            final List<String> errors = scanDirectory(broker, transaction, packageDir, targetCollection, resources, true, false, requestedPerms);
            // store repo.xml, filtering out the default user's password
            storeRepoXML(broker, transaction, repoXML, targetCollection, requestedPerms);
            // run the post-setup query if present
            final Optional<ElementImpl> postSetup = findElement(repoXML, POST_SETUP_ELEMENT);
            final Optional<String> postSetupPath = postSetup.map(ElementImpl::getStringValue).filter(s -> !s.isEmpty());
            if (postSetupPath.isPresent()) {
                runQuery(broker, targetCollection, packageDir, postSetupPath.get(), pkgName, QueryPurpose.POSTINSTALL);
            }
            if (!errors.isEmpty()) {
                throw new PackageException("Deployment incomplete, " + errors.size() + " issues found: " + String.join("; ", errors));
            }
            return Optional.ofNullable(targetCollection.getCollectionPath());
        }
    } catch (final XPathException e) {
        throw new PackageException("Error found while processing repo.xml: " + e.getMessage(), e);
    }
}
Also used : Path(java.nio.file.Path) DependencyVersion(org.expath.pkg.repo.deps.DependencyVersion) Txn(org.exist.storage.txn.Txn) java.util(java.util) BufferedInputStream(java.io.BufferedInputStream) QName(org.exist.dom.QName) SequenceIterator(org.exist.xquery.value.SequenceIterator) PermissionDeniedException(org.exist.security.PermissionDeniedException) org.exist.xquery(org.exist.xquery) DirectoryStream(java.nio.file.DirectoryStream) JarEntry(java.util.jar.JarEntry) org.exist.dom.memtree(org.exist.dom.memtree) Collection(org.exist.collections.Collection) UnixStylePermission(org.exist.security.UnixStylePermission) XmldbURI(org.exist.xmldb.XmldbURI) Attributes(org.xml.sax.Attributes) JarInputStream(java.util.jar.JarInputStream) EXistException(org.exist.EXistException) DocUtils(org.exist.xquery.util.DocUtils) DateTimeValue(org.exist.xquery.value.DateTimeValue) SystemProperties(org.exist.SystemProperties) Path(java.nio.file.Path) Permission(org.exist.security.Permission) Nullable(javax.annotation.Nullable) BatchUserInteraction(org.expath.pkg.repo.tui.BatchUserInteraction) PermissionFactory(org.exist.security.PermissionFactory) InputSource(org.xml.sax.InputSource) Files(java.nio.file.Files) GroupAider(org.exist.security.internal.aider.GroupAider) Type(org.exist.xquery.value.Type) FileSource(org.exist.source.FileSource) IOException(java.io.IOException) UserAider(org.exist.security.internal.aider.UserAider) Either(com.evolvedbinary.j8fu.Either) org.expath.pkg.repo(org.expath.pkg.repo) Logger(org.apache.logging.log4j.Logger) Element(org.w3c.dom.Element) Stream(java.util.stream.Stream) DBBroker(org.exist.storage.DBBroker) SAXException(org.xml.sax.SAXException) org.exist.util(org.exist.util) Sequence(org.exist.xquery.value.Sequence) TriggerException(org.exist.collections.triggers.TriggerException) LogManager(org.apache.logging.log4j.LogManager) Package(org.expath.pkg.repo.Package) AttrList(org.exist.util.serializer.AttrList) InputStream(java.io.InputStream) Either(com.evolvedbinary.j8fu.Either) Package(org.expath.pkg.repo.Package) XmldbURI(org.exist.xmldb.XmldbURI)

Example 37 with XmldbURI

use of org.exist.xmldb.XmldbURI in project exist by eXist-db.

the class EmbeddedOutputStream method uploadToDb.

private static void uploadToDb(final BrokerPool pool, final XmldbURL url, final Path tempFile) throws IOException {
    try (final DBBroker broker = pool.getBroker()) {
        final XmldbURI collectionUri = XmldbURI.create(url.getCollection());
        final XmldbURI documentUri = XmldbURI.create(url.getDocumentName());
        try (final Collection collection = broker.openCollection(collectionUri, Lock.LockMode.WRITE_LOCK)) {
            if (collection == null) {
                throw new IOException("Resource " + collectionUri.toString() + " is not a collection.");
            }
            if (collection.hasChildCollection(broker, documentUri)) {
                throw new IOException("Resource " + documentUri.toString() + " is a collection.");
            }
            final MimeType mime = MimeTable.getInstance().getContentTypeFor(documentUri);
            final TransactionManager transact = pool.getTransactionManager();
            try (final Txn txn = transact.beginTransaction()) {
                broker.storeDocument(txn, documentUri, new FileInputSource(tempFile), mime, collection);
                txn.commit();
            }
        }
    } catch (final EXistException | PermissionDeniedException | LockException | SAXException e) {
        LOG.error(e);
        throw new IOException(e.getMessage(), e);
    } finally {
        if (LOG.isDebugEnabled()) {
            LOG.debug("End document upload");
        }
    }
}
Also used : Txn(org.exist.storage.txn.Txn) EXistException(org.exist.EXistException) SAXException(org.xml.sax.SAXException) DBBroker(org.exist.storage.DBBroker) TransactionManager(org.exist.storage.txn.TransactionManager) Collection(org.exist.collections.Collection) PermissionDeniedException(org.exist.security.PermissionDeniedException) XmldbURI(org.exist.xmldb.XmldbURI)

Example 38 with XmldbURI

use of org.exist.xmldb.XmldbURI in project exist by eXist-db.

the class NativeBroker method reindexCollection.

@Override
public void reindexCollection(final Txn transaction, final XmldbURI collectionUri) throws PermissionDeniedException, IOException, LockException {
    if (isReadOnly()) {
        throw new IOException(DATABASE_IS_READ_ONLY);
    }
    final XmldbURI fqUri = prepend(collectionUri.toCollectionPathURI());
    final long start = System.currentTimeMillis();
    try (final Collection collection = openCollection(fqUri, LockMode.READ_LOCK)) {
        if (collection == null) {
            LOG.warn("Collection {} not found!", fqUri);
            return;
        }
        LOG.info("Start indexing collection {}", collection.getURI().toString());
        pool.getProcessMonitor().startJob(ProcessMonitor.ACTION_REINDEX_COLLECTION, collection.getURI());
        reindexCollection(transaction, collection, IndexMode.STORE);
    } catch (final PermissionDeniedException | IOException e) {
        LOG.error("An error occurred during reindex: {}", e.getMessage(), e);
    } finally {
        pool.getProcessMonitor().endJob();
        LOG.info("Finished indexing collection {} in {} ms.", fqUri, System.currentTimeMillis() - start);
    }
}
Also used : Collection(org.exist.collections.Collection) XmldbURI(org.exist.xmldb.XmldbURI)

Example 39 with XmldbURI

use of org.exist.xmldb.XmldbURI in project exist by eXist-db.

the class NativeBroker method lockDescendantDocuments.

/**
 * Acquires locks on all descendant Collections of a specific Collection
 *
 * Locks are acquired in a top-down, left-to-right order
 *
 * NOTE: It is assumed that the caller holds a lock on the
 *     `collection` of the same mode as those that we should acquire on the descendants
 *
 * @param collection The Collection whose descendant locks should be acquired
 * @param lockFn A function for acquiring a lock
 *
 * @return A list of locks in the same order as collectionUris. Note that these should be released in reverse order
 */
private List<ManagedDocumentLock> lockDescendantDocuments(final Collection collection, final FunctionE<XmldbURI, ManagedDocumentLock, LockException> lockFn) throws LockException, PermissionDeniedException {
    final List<ManagedDocumentLock> locks = new ArrayList<>();
    try {
        final Iterator<DocumentImpl> itDoc = collection.iteratorNoLock(this);
        while (itDoc.hasNext()) {
            final DocumentImpl doc = itDoc.next();
            final ManagedDocumentLock docLock = lockFn.apply(doc.getURI());
            locks.add(docLock);
        }
        final XmldbURI collectionUri = collection.getURI();
        // NOTE: we should already have a lock on collection
        final Iterator<XmldbURI> it = collection.collectionIteratorNoLock(this);
        while (it.hasNext()) {
            final XmldbURI childCollectionName = it.next();
            final XmldbURI childCollectionUri = collectionUri.append(childCollectionName);
            // NOTE: we don't need to lock the collection as we should already implicitly have a lock on the collection sub-tree
            final Collection childCollection = getCollection(childCollectionUri);
            final List<ManagedDocumentLock> descendantLocks = lockDescendantDocuments(childCollection, lockFn);
            locks.addAll(descendantLocks);
        }
    } catch (final PermissionDeniedException | LockException e) {
        // unlock in reverse order
        try {
            ManagedLocks.closeAll(locks);
        } catch (final RuntimeException re) {
            LOG.error(re);
        }
        throw e;
    }
    return locks;
}
Also used : Collection(org.exist.collections.Collection) XmldbURI(org.exist.xmldb.XmldbURI)

Example 40 with XmldbURI

use of org.exist.xmldb.XmldbURI in project exist by eXist-db.

the class NativeBroker method copyResource.

@Override
public void copyResource(final Txn transaction, final DocumentImpl sourceDocument, final Collection targetCollection, final XmldbURI newDocName, final PreserveType preserve) throws PermissionDeniedException, LockException, IOException, TriggerException, EXistException {
    assert (sourceDocument != null);
    assert (targetCollection != null);
    assert (newDocName != null);
    if (isReadOnly()) {
        throw new IOException(DATABASE_IS_READ_ONLY);
    }
    if (newDocName.numSegments() != 1) {
        throw new IOException("newName name must be just a name i.e. an XmldbURI with one segment!");
    }
    final XmldbURI sourceDocumentUri = sourceDocument.getURI();
    final XmldbURI targetCollectionUri = targetCollection.getURI();
    final XmldbURI targetDocumentUri = targetCollectionUri.append(newDocName);
    if (!sourceDocument.getPermissions().validate(getCurrentSubject(), Permission.READ)) {
        throw new PermissionDeniedException("Account '" + getCurrentSubject().getName() + "' has insufficient privileges to copy the resource '" + sourceDocumentUri + "'.");
    }
    // we assume the caller holds a READ_LOCK (or better) on sourceDocument#getCollection()
    final Collection sourceCollection = sourceDocument.getCollection();
    if (!sourceCollection.getPermissions().validate(getCurrentSubject(), Permission.EXECUTE)) {
        throw new PermissionDeniedException("Account '" + getCurrentSubject().getName() + "' has insufficient privileges to copy the resource '" + sourceDocumentUri + "'.");
    }
    if (!targetCollection.getPermissionsNoLock().validate(getCurrentSubject(), Permission.EXECUTE)) {
        throw new PermissionDeniedException("Account '" + getCurrentSubject().getName() + "' does not have execute access on the destination collection '" + targetCollectionUri + "'.");
    }
    if (targetCollection.hasChildCollection(this, newDocName.lastSegment())) {
        throw new EXistException("The collection '" + targetCollectionUri + "' already has a sub-collection named '" + newDocName.lastSegment() + "', you cannot create a Document with the same name as an existing collection.");
    }
    try (final LockedDocument oldLockedDoc = targetCollection.getDocumentWithLock(this, newDocName, LockMode.WRITE_LOCK)) {
        final DocumentTrigger trigger = new DocumentTriggers(this, transaction, targetCollection);
        final DocumentImpl oldDoc = oldLockedDoc == null ? null : oldLockedDoc.getDocument();
        if (oldDoc == null) {
            if (!targetCollection.getPermissionsNoLock().validate(getCurrentSubject(), Permission.WRITE)) {
                throw new PermissionDeniedException("Account '" + getCurrentSubject().getName() + "' does not have write access on the destination collection '" + targetCollectionUri + "'.");
            }
        } else {
            if (sourceDocument.getDocId() == oldDoc.getDocId()) {
                throw new PermissionDeniedException("Cannot copy resource to itself '" + sourceDocumentUri + "'.");
            }
            if (!oldDoc.getPermissions().validate(getCurrentSubject(), Permission.WRITE)) {
                throw new PermissionDeniedException("A resource with the same name already exists in the target collection '" + oldDoc.getURI() + "', and you do not have write access on that resource.");
            }
            trigger.beforeDeleteDocument(this, transaction, oldDoc);
            trigger.afterDeleteDocument(this, transaction, targetDocumentUri);
        }
        doCopyDocument(transaction, trigger, sourceDocument, targetCollection, newDocName, oldDoc, preserve);
    }
}
Also used : Collection(org.exist.collections.Collection) EXistException(org.exist.EXistException) XmldbURI(org.exist.xmldb.XmldbURI)

Aggregations

XmldbURI (org.exist.xmldb.XmldbURI)260 Collection (org.exist.collections.Collection)100 PermissionDeniedException (org.exist.security.PermissionDeniedException)69 Test (org.junit.Test)56 Txn (org.exist.storage.txn.Txn)55 EXistException (org.exist.EXistException)42 URISyntaxException (java.net.URISyntaxException)39 LockedDocument (org.exist.dom.persistent.LockedDocument)39 IOException (java.io.IOException)38 DBBroker (org.exist.storage.DBBroker)38 DocumentImpl (org.exist.dom.persistent.DocumentImpl)34 SAXException (org.xml.sax.SAXException)33 Permission (org.exist.security.Permission)30 LockException (org.exist.util.LockException)27 Path (java.nio.file.Path)22 XPathException (org.exist.xquery.XPathException)22 BrokerPool (org.exist.storage.BrokerPool)21 TransactionManager (org.exist.storage.txn.TransactionManager)20 Subject (org.exist.security.Subject)19 StringInputSource (org.exist.util.StringInputSource)17