diff --git a/.classpath b/.classpath
index 5ad163ae880..918957e788e 100644
--- a/.classpath
+++ b/.classpath
@@ -22,7 +22,7 @@
-
+
@@ -31,13 +31,14 @@
-
+
+
@@ -59,9 +60,11 @@
+
+
@@ -113,7 +116,7 @@
-
+
@@ -128,7 +131,7 @@
-
+
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 12713a9820a..ef86d22c564 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -6,7 +6,7 @@ To help the community judge your pull request (PR), please include the following
- A context reference to a [Github Issue](https://github.com/eXist-db/exist/issues), a message in the [eXist-open mailinglist](http://exist-open.markmail.org), or a [specification](https://www.w3.org/TR/xquery-31/).
- Tests. The [XQSuite - Annotation-based Test Framework for XQuery](http://exist-db.org/exist/apps/doc/xqsuite.xml) makes it very easy for you to create tests. These tests can be executed from the [eXide editor](http://exist-db.org/exist/apps/eXide/index.html) via XQuery > Run as Test.
-Your PR will be tested using [Travis CI](https://travis-ci.org/eXist-db/exist) and [AppVeyor](https://ci.appveyor.com/project/AdamRetter/exist) against a number of operating systems and environments. The build status is visible in the PR.
+Your PR will be tested using [Travis CI](https://travis-ci.com/eXist-db/exist) and [AppVeyor](https://ci.appveyor.com/project/AdamRetter/exist) against a number of operating systems and environments. The build status is visible in the PR.
To detect errors in your PR before submitting it, please run eXist's full test suite on your own system via `build.sh test`.
diff --git a/.gitignore b/.gitignore
index 57d6e4210ae..b316f958d0c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,7 +46,6 @@ nbproject/private/
start.jar
test/external/
test/junit/
-test/src/org/exist/xquery/xqts/
test/temp/
tools/jetty/logs/
tools/jetty/tmp/
@@ -71,7 +70,6 @@ webapp/WEB-INF/dwr20.dtd
webapp/WEB-INF/logs/*.log
webapp/WEB-INF/logs/*.log.*
webapp/WEB-INF/web.xml
-webapp/xqts/config.xml
tools/yajsw/logs/wrapper.log
tools/yajsw/logs/wrapper.log.lck
Project_Default.xml
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 5e7e131601f..93ab7df3305 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/.travis.yml b/.travis.yml
index 823e524ad3f..37e0d0853b1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,10 +4,17 @@ matrix:
include:
- jdk: openjdk8
- jdk: oraclejdk8
- - jdk: oraclejdk9
+ - jdk: openjdk9
+ - jdk: openjdk10
+ - jdk: openjdk11
+# - jdk: oraclejdk11
- os: osx
osx_image: xcode9.2
env: JAVA_HOME=$(/usr/libexec/java_home)
script: ./build.sh -Dexist.autodeploy=off -Dtest.haltonerror=true -Dtest.haltonfailure=true clean clean-all all test
+cache:
+ directories:
+ - $HOME/.ivy2
+ - $HOME/.m2
notifications:
hipchat: ec8fcfa661addc56a361a8ef536320@integrations
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000000..fd558d01073
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,77 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, sex characteristics, gender identity and expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at info@exist-db.org. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
+
diff --git a/README.md b/README.md
index eacc6cff7fd..e043f69f75c 100644
--- a/README.md
+++ b/README.md
@@ -4,9 +4,9 @@
-## eXist Native XML Database
+## eXist-db Native XML Database
-[](https://travis-ci.org/eXist-db/exist)
+[](https://travis-ci.com/eXist-db/exist)
[](https://ci.appveyor.com/project/AdamRetter/exist/branch/develop)
[](https://www.codacy.com/app/eXist-db/exist?utm_source=github.com&utm_medium=referral&utm_content=eXist-db/exist&utm_campaign=Badge_Grade)
[](http://java.oracle.com)
@@ -14,7 +14,11 @@
[](https://bintray.com/existdb/releases/exist/_latestVersion)
[](https://www.hipchat.com/gEBQ3SNfp)
-eXist is a high-performance open source native XML database—a NoSQL document database and application platform built entirely around XML technologies. The main homepage for eXist can be found at [exist-db.org](http://www.exist-db.org "eXist Homepage"). This is the GitHub repository of eXist source code, and this page links to resources for downloading, building, and contributing to eXist, below.
+[](http://contributor-covenant.org/version/1/4/)
+
+eXist-db is a high-performance open source native XML database—a NoSQL document database and application platform built entirely around XML technologies. The main homepage for eXist-db can be found at [exist-db.org](http://www.exist-db.org "eXist Homepage"). This is the GitHub repository of eXist source code, and this page links to resources for downloading, building, and contributing to eXist-db, below.
+
+The eXist-db community has adopted the [Contributor Covenant](https://www.contributor-covenant.org/) [Code of Conduct](https://www.contributor-covenant.org/version/1/4/code-of-conduct).
## Resources
diff --git a/appveyor.yml b/appveyor.yml
index 92eb499ee54..d9aeda72710 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -8,9 +8,8 @@ environment:
JAVA_HOME: C:\Program Files\Java\jdk9
- APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu
JAVA_HOME: /usr/lib/jvm/java-8-openjdk-amd64
-# Disabled Ubuntu OpenJDK due to AspectJ bug - https://bugs.eclipse.org/bugs/show_bug.cgi?id=534801
-# - APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu
-# JAVA_HOME: /usr/lib/jvm/java-9-openjdk-amd64
+ - APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu
+ JAVA_HOME: /usr/lib/jvm/java-9-openjdk-amd64
- APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu
JAVA_HOME: /usr/lib/jvm/java-10-openjdk-amd64
diff --git a/bin/functions.d/eXist-settings.sh b/bin/functions.d/eXist-settings.sh
index 51c1857a7b2..e237bc33208 100755
--- a/bin/functions.d/eXist-settings.sh
+++ b/bin/functions.d/eXist-settings.sh
@@ -1,6 +1,8 @@
-# -*-Shell-script-*-
-# Common eXist script functions and settings
-# $Id:eXist-settings.sh 7231 2008-01-14 22:33:35Z wolfgang_m $
+#!/usr/bin/env bash
+
+##
+# Common eXist-db script functions and settings
+##
get_exist_home() {
case "$1" in
diff --git a/bin/functions.d/getopt-settings.sh b/bin/functions.d/getopt-settings.sh
index a672e68f987..f5095643991 100755
--- a/bin/functions.d/getopt-settings.sh
+++ b/bin/functions.d/getopt-settings.sh
@@ -1,6 +1,8 @@
-# -*-Shell-script-*-
-# Common eXist script functions and settings for getopt
-# $Id$
+#!/usr/bin/env bash
+
+##
+# Common eXist-db script functions and settings for getopt
+##
CLIENT_OPTS="|-u|--user|-P|--password|-p|--parse|-C|--config|-r|--remove|-c|--collection|-f|--resource|-g|--get|-m|--mkcol|-R|--rmcol|-x|--xpath|-n|--howmany|-o|--option|-O|--output|-F|--file|-t|--threads|-X|--xupdate|-T|--trace|"
@@ -26,100 +28,98 @@ declare -a JAVA_OPTS
declare -a CLIENT_PROPS
substring() {
- [ "${1#*$2*}" = "$1" ] && return 1
- return 0
+ [ "${1#*$2*}" = "$1" ] && return 1
+ return 0
}
is_integer() {
- [ $1 -eq 1 ] 2> /dev/null;
- if [ $? -eq 2 ]; then
- echo "Port need to be an integer" > /dev/stderr;
- exit 1
- fi
- return 0
+ [ $1 -eq 1 ] 2> /dev/null;
+ if [ $? -eq 2 ]; then
+ echo "Port need to be an integer" > /dev/stderr;
+ exit 1
+ fi
+ return 0
}
is_jmx_switch() {
- if substring "${JMX_OPTS}" "|$1|"; then
- JMX_ENABLED=1;
- return 0;
- elif substring "|$1|" "$JMX_SHORT_EQUAL"; then
- JMX_ENABLED=1;
- JMX_PORT="${1#${JMX_SHORT_EQUAL}}" && is_integer "${JMX_PORT}";
- return 0;
- elif substring "|$1|" "${JMX_LONG_EQUAL}"; then
- JMX_ENABLED=1;
- JMX_PORT="${1#${JMX_LONG_EQUAL}}" && is_integer "${JMX_PORT}";
- return 0;
- elif substring "|$1|" "${JMX_SHORT}"; then
- JMX_ENABLED=1;
- JMX_PORT="${1#${JMX_SHORT}}" && is_integer "${JMX_PORT}";
- return 0;
- elif substring "|$1|" "${JMX_LONG}"; then
- JMX_ENABLED=1;
- JMX_PORT="${1#${JMX_LONG}}" && is_integer "${JMX_PORT}";
- return 0;
- fi
- return 1;
+ if substring "${JMX_OPTS}" "|$1|"; then
+ JMX_ENABLED=1;
+ return 0;
+ elif substring "|X$1|" "X$JMX_SHORT_EQUAL"; then
+ JMX_ENABLED=1;
+ JMX_PORT="${1#${JMX_SHORT_EQUAL}}" && is_integer "${JMX_PORT}";
+ return 0;
+ elif substring "|X$1|" "X${JMX_LONG_EQUAL}"; then
+ JMX_ENABLED=1;
+ JMX_PORT="${1#${JMX_LONG_EQUAL}}" && is_integer "${JMX_PORT}";
+ return 0;
+ elif substring "|X$1|" "X${JMX_SHORT}"; then
+ JMX_ENABLED=1;
+ JMX_PORT="${1#${JMX_SHORT}}" && is_integer "${JMX_PORT}";
+ return 0;
+ elif substring "|X$1|" "X${JMX_LONG}"; then
+ JMX_ENABLED=1;
+ JMX_PORT="${1#${JMX_LONG}}" && is_integer "${JMX_PORT}";
+ return 0;
+ fi
+ return 1;
}
check_quiet_switch() {
- if substring "${QUIET_OPTS}" "|$1|"; then
- QUIET_ENABLED=1;
- fi
+ if substring "${QUIET_OPTS}" "|$1|"; then
+ QUIET_ENABLED=1;
+ fi
}
get_opts() {
- local -a ALL_OPTS=( "$@" )
- local found_jmx_opt
- local found_pidfile_opt
-
- for OPT in "${ALL_OPTS[@]}" ; do
- if [ -n "$found_jmx_opt" ] ; then
- unset found_jmx_opt
- local found_jmx_opt
- if ! substring "${OPT}" $"-" && is_integer "${OPT}"; then
- JMX_PORT="$OPT"
- continue
- fi
- elif [ -n "$found_pidfile_opt" ]; then
- unset found_pidfile_opt
- PIDFILE=$OPT
- continue
- fi
-
- if [ $OPT == "--forking" ]; then
- FORKING=1
- continue
- fi
-
- if is_jmx_switch "$OPT"; then
- found_jmx_opt=1
- elif [ $OPT == "--pidfile" ]; then
- found_pidfile_opt=1
- else
- check_quiet_switch "$OPT";
- JAVA_OPTS[${NR_JAVA_OPTS}]="$OPT";
- let "NR_JAVA_OPTS += 1";
- fi
- done
-
- if [ "${QUIET_ENABLED}" -eq 0 ]; then
- echo "${JAVA_OPTS[@]}";
- fi
+ local -a ALL_OPTS=( "$@" )
+ local found_jmx_opt
+ local found_pidfile_opt
+
+ for OPT in "${ALL_OPTS[@]}" ; do
+ if [ -n "$found_jmx_opt" ] ; then
+ unset found_jmx_opt
+ local found_jmx_opt
+ if ! substring "${OPT}" $"-" && is_integer "${OPT}"; then
+ JMX_PORT="$OPT"
+ continue
+ fi
+ elif [ -n "$found_pidfile_opt" ]; then
+ unset found_pidfile_opt
+ PIDFILE=$OPT
+ continue
+ fi
+
+ if [ $OPT == "--forking" ]; then
+ FORKING=1
+ continue
+ fi
+
+ if is_jmx_switch "$OPT"; then
+ found_jmx_opt=1
+ elif [ $OPT == "--pidfile" ]; then
+ found_pidfile_opt=1
+ else
+ check_quiet_switch "$OPT";
+ JAVA_OPTS[${NR_JAVA_OPTS}]="$OPT";
+ let "NR_JAVA_OPTS += 1";
+ fi
+ done
+
+ if [ "${QUIET_ENABLED}" -eq 0 ]; then
+ echo "${JAVA_OPTS[@]}";
+ fi
}
get_client_props() {
- shopt -s extglob
- while IFS="=" read -r key value
- do
- case "${key}" in
- \#* ) ;;
- * )
- #echo "Read client properties key: ${key}, value: ${value}"
- CLIENT_PROPS["${key}"]="${value}"
- ;;
- esac
-done < ${EXIST_HOME}/client.properties
-
+ shopt -s extglob
+ while IFS="=" read -r key value; do
+ case "${key}" in
+ \#* ) ;;
+ * )
+ #echo "Read client properties key: ${key}, value: ${value}"
+ CLIENT_PROPS["${key}"]="${value}"
+ ;;
+ esac
+ done < ${EXIST_HOME}/client.properties
}
diff --git a/bin/functions.d/jmx-settings.sh b/bin/functions.d/jmx-settings.sh
index 40d31c86d94..71e7b6f1845 100755
--- a/bin/functions.d/jmx-settings.sh
+++ b/bin/functions.d/jmx-settings.sh
@@ -1,6 +1,8 @@
-# -*-Shell-script-*-
-# Common eXist script functions and settings for JMX
-# $Id:jmx-settings.sh 7231 2008-01-14 22:33:35Z wolfgang_m $
+#!/usr/bin/env bash
+
+##
+# Common eXist-db script functions and settings for JMX
+##
JMX_ENABLED=0
JMX_PORT=1099
diff --git a/build.properties b/build.properties
index 8dcbe0dd9b0..ff0caacbfae 100644
--- a/build.properties
+++ b/build.properties
@@ -4,7 +4,7 @@
#
# $Id$
project.name = eXist-db
-project.version = 4.3.0-SNAPSHOT
+project.version = 5.0.0-SNAPSHOT
# db settings
config.dataDir = webapp/WEB-INF/data
@@ -27,6 +27,9 @@ keystore.password = secret
keystore.file = key.store
keystore.validity = 100000
+# The EnsureLockAspect enforces the locking contracts by annotation
+enable.ensurelocking.aspect=false
+
autodeploy=dashboard,shared,eXide,monex,functx,usermanager
autodeploy.repo=http://demo.exist-db.org/exist/apps/public-repo
use.autodeploy.feature=true
@@ -35,11 +38,6 @@ use.autodeploy.feature=true
junit.reports = test
junit.output = true
junit.forked.VM.maxmemory = 512m
-# Converted junit tests from external testsuites
-# reuire more memory, e g
-# XSLTS requires 512m
-# XQTS requires more than 400m
-junit.forked.VM.maxmemory.external = 512m
proxy.nonproxyhosts =
proxy.host =
proxy.port = 0
@@ -80,9 +78,6 @@ antlr.traceTreeWalker = false
# You might need to change PermSpace to atleast 84 MB eg -XX:MaxPermSize=84m
# If you only want to point to your own izpack installation directory
# add this in local.build.properties instead so you don't commit it by mistake.
-#
-# For generating the MacOSX bundle please download the "Java Application Bundler" from
-# https://java.net/projects/appbundler (store in IzPack/lib)
izpack.dir = /Applications/IzPack/
# If you wish to sign .app applications and .DMG packages for MacOS
diff --git a/build/scripts/build-impl.xml b/build/scripts/build-impl.xml
index 40102b9f8be..8ded8dedb4e 100644
--- a/build/scripts/build-impl.xml
+++ b/build/scripts/build-impl.xml
@@ -36,7 +36,6 @@
-
@@ -100,7 +99,7 @@
-
+
@@ -168,9 +167,6 @@
-
-
@@ -217,7 +213,8 @@
-
+
+
@@ -271,6 +268,7 @@
+
@@ -296,6 +294,9 @@
+
+
+
@@ -742,12 +743,6 @@
-
-
-
-
-
-
@@ -799,7 +794,6 @@
-
@@ -809,11 +803,6 @@
-
-
-
-
-
diff --git a/build/scripts/dist.xml b/build/scripts/dist.xml
index 7654941e59f..2c7f61fb4ff 100644
--- a/build/scripts/dist.xml
+++ b/build/scripts/dist.xml
@@ -219,144 +219,119 @@
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
+
+
-
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
-
-
-
-
-
-
+
-
+
+
+
-
+
+
+
-
-
+
+
@@ -368,27 +343,71 @@
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/build/scripts/jarsigner.xml b/build/scripts/jarsigner.xml
index 2e586ac230c..0d87bc77da6 100644
--- a/build/scripts/jarsigner.xml
+++ b/build/scripts/jarsigner.xml
@@ -62,6 +62,9 @@
+
+
+
@@ -134,6 +137,9 @@
+
+
+
@@ -181,7 +187,7 @@
-
+
diff --git a/build/scripts/junit.xml b/build/scripts/junit.xml
index 6b3587f3160..48f2aff8dd3 100644
--- a/build/scripts/junit.xml
+++ b/build/scripts/junit.xml
@@ -182,6 +182,7 @@
+
@@ -204,7 +205,13 @@
-
+
+
+
+
+
+
+
@@ -289,6 +296,9 @@
+
+
+
@@ -442,140 +452,4 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- JUnit tests generated.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- JUnit tests generated.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/build/scripts/macosx.xml b/build/scripts/macosx.xml
index 91ea2afa526..0b71e955f27 100644
--- a/build/scripts/macosx.xml
+++ b/build/scripts/macosx.xml
@@ -13,11 +13,11 @@
-
+
-
+
@@ -171,7 +171,6 @@
-
diff --git a/build/scripts/setup.xml b/build/scripts/setup.xml
index ecb847fdc20..7690423d43c 100644
--- a/build/scripts/setup.xml
+++ b/build/scripts/setup.xml
@@ -46,6 +46,7 @@
Download xar files from the package website.
-->
+
@@ -55,6 +56,10 @@
+
+
+
+
diff --git a/conf.xml.tmpl b/conf.xml.tmpl
index d5329fb3b4d..b32af81063c 100644
--- a/conf.xml.tmpl
+++ b/conf.xml.tmpl
@@ -138,6 +138,7 @@
If you need stable, incremental ids, set the option doc-ids to
"incremental".
+
- minDiskSpace:
The amount of disk space (in megabytes) which should be available for
the database to continue operations. If free disk space goes below
@@ -145,6 +146,47 @@
switch to read-only mode in order to prevent potential data loss.
Set the limit large enough to allow all pending operations to
complete. The default is 1 gigabyte.
+
+ - posix-chown-restricted:
+ As defined by POSIX.1 for _POSIX_CHOWN_RESTRICTED.
+
+ When posix-chown-restricted="true" (the default) then:
+ 1. Only a superuser process can change the user ID of the file.
+ 2. A non-superuser process can change the group ID of the file
+ if the process owns the file (the effective user ID equals
+ the user ID of the file), and group equals either the
+ effective group ID of the process or one of the
+ process’s supplementary group IDs.
+ This means that when posix-chown-restricted="true", you can’t change
+ the user ID of your files. You can change the group ID of files that
+ you own, but only to groups that you belong to.
+
+ When posix-chown-restricted="false" you can change the user ID of
+ any file that you own, effectively "giving away the file" to
+ another user. Such a setting has negative security implications,
+ further details can be seen in the "Rationale" section for the
+ chown function in the POSIX.1-2017 (Issue 7, 2018 edition) standard.
+ See: http://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html#tag_16_59_07
+
+ - preserve-on-copy
+ When copying Collections and Documents within the database, the
+ default (`false`), is not to preserve their attributes
+ (modification time, mode, user-id, group-id, and ACL).
+
+ NOTE: Not preserving attributes, is inline with both the GNU and
+ BSD `cp` commands, and therefore expected behaviour; The target
+ Collection or Document is created following the rules of the
+ target parent, and the effective user and their umask.
+
+ Setting preserve-on-copy="true" changes the default behaviour
+ so that the target Collection or Document of a copy, has the same
+ attributes as the source.
+
+ The preserve-on-copy setting can be overridden on a case-by-case
+ basis by setting the `preserve` flag to either `true` or `false`
+ when calling xmldb:copy(), or via any other API that supports copy.
+ Omitting the preserve flag when calling a copy operation, implies
+ the behaviour that is set in this configuration.
=====================================================================
@@ -157,7 +199,7 @@
-->
+ doc-ids="default" minDiskSpace="128M" posix-chown-restricted="true" preserve-on-copy="false">
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/exist-versioning-release.md b/exist-versioning-release.md
index 89d01fb922b..cbddad928f3 100644
--- a/exist-versioning-release.md
+++ b/exist-versioning-release.md
@@ -122,7 +122,11 @@ Once development on a new stable version is complete, the following steps will p
project.version = 3.1.0
```
- And commit the changes and push to `origin` (or `upstream` if you are on a fork).
+ And commit the changes and push to `origin` (or `upstream` if you are on a fork):
+ ```
+ $ git commit build.properties -m "[release] Set version for 3.1.0 release"
+ $ git push origin/develop
+ ```
4. Git tag **and sign** eXist-3.1.0 from the `HEAD` of `develop` branch and push the tag to `origin` (or `upstream` if you are on a fork):
```
@@ -139,7 +143,11 @@ Once development on a new stable version is complete, the following steps will p
project.version = 3.2.0-SNAPSHOT
```
- And commit the changes and push to `origin` (or `upstream` if you are on a fork).
+ And commit the changes and push to `origin` (or `upstream` if you are on a fork):
+ ```
+ $ git commit build.properties -m "[release] Set version to 3.2.0-SNAPSHOT"
+ $ git push origin/develop
+ ```
**NOTE:** We increment to the next `MINOR` version, rather than to the next `PATCH` or `MAJOR` version, for two reasons. First, we assume the next version will likely contain features and not just bug patches, although this does not prevent us from doing a `3.1.1` (a `PATCH` release) release next, should we have only patches. By the same token, the future is uncertain and we recognise that it is easier to release features with non-breaking API changes and patches, although this still does not prevent us from doing a `4.0.0` release next, should we have breaking API changes.
@@ -166,19 +174,21 @@ Once development on a new stable version is complete, the following steps will p
4. Perform the build of the tag:
```
$ git checkout eXist-3.1.0
- $ ./build.sh jnlp-unsign-all all jnlp-sign-exist jnlp-sign-core jnlp-sign-exist-extensions
- $ ./build.sh installer app-signed dist-war
+ $ ./build.sh clean clean-all jnlp-unsign-all all jnlp-sign-exist jnlp-sign-core jnlp-sign-exist-extensions
+ $ ./build.sh installer app-signed dist-war dist-bz2
```
#### Publishing the Product Release
-1. Login to https://bintray.com/existdb/ and create a new "Version", then upload the files `$EXIST_HOME/installer/eXist-db-setup-3.2.0.jar`, `$EXIST_HOME/dist/eXist-db-3.2.0.dmg` and `$EXIST_HOME/dist/exist-3.1.0.war`. Once the files have uploaded, make sure to click "Publish" to publish them to the version. Once published, you need to go to the "Files" section of the version, and click "Actions"->"Show in downloads list" for each file.
+1. Login to https://bintray.com/existdb/ and create a new "Version", then upload the files `$EXIST_HOME/installer/eXist-db-setup-3.2.0.jar`, `$EXIST_HOME/dist/eXist-db-3.2.0.dmg`, `$EXIST_HOME/dist/exist-3.1.0.war`, and `$EXIST_HOME/dist/exist-3.1.0.tar.bz2`. Once the files have uploaded, make sure to click "Publish" to publish them to the version. Once published, you need to go to the "Files" section of the version, and click "Actions"->"Show in downloads list" for each file.
2. Update and publish the latest Maven artifacts as described here: https://github.com/exist-db/mvn-repo
3. Ask [Evolved Binary](http://www.evolvedbinary.com) to build and upload new Docker Images for the latest release.
-4. Edit the links for the downloads on the eXist website.
+4. Update the Mac HomeBrew for eXist-db, see: [Releasing to Homebrew](https://github.com/eXist-db/exist/blob/develop/exist-versioning-release.md#releasing-to-homebrew).
+
+5. Edit the links for the downloads on the eXist website.
1. `$ git clone https://github.com/exist-db/website.git`
@@ -218,7 +228,7 @@ Once development on a new stable version is complete, the following steps will p
```
- 3. Edit the file `expath-pkg.xml` and modify `version="3.1.0"` to reflect the new version.
+ 3. Edit the file `expath-pkg.xml` and bump the version i.e. `version="4"` to reflect the new version.
4. Commit your change and push: `$ git commit index.html expath-pkg.xml -m "Update for eXist-3.1.0 website" && git push origin master`
@@ -228,17 +238,21 @@ Once development on a new stable version is complete, the following steps will p
7. Visit http://www.exist-db.org/exist/apps/dashboard/index.html, login and upload the new `build/homepage.xar` file via the Package Manager.
-5. Login to the blog at http://exist-db.org/exist/apps/wiki/blogs/eXist/ and add a new news item which announces the release and holds the release notes. It should be named like http://exist-db.org/exist/apps/wiki/blogs/eXist/eXistdb310
+6. Login to the blog at http://exist-db.org/exist/apps/wiki/blogs/eXist/ and add a new news item which announces the release and holds the release notes. It should be named like http://exist-db.org/exist/apps/wiki/blogs/eXist/eXistdb310
+
+7. Visit the GitHub releases page https://github.com/eXist-db/exist/releases and create a new release, enter the tag you previously created and link the release notes from the blog and the binaries from BinTray.
+
+8. Send an email to the `exist-open` mailing list announcing the release with a title similar to `[ANN] Release of eXist 3.1.0`, copy and paste the release notes from the blog into the email and reformat appropriately (see past emails).
-6. Visit the GitHub releases page https://github.com/eXist-db/exist/releases and create a new release, enter the tag you previously created and link the release notes from the blog and the binaries from BinTray.
+9. Tweet about it using the `existdb` twitter account.
-7. Send an email to the `exist-open` mailing list announcing the release with a title similar to `[ANN] Release of eXist 3.1.0`, copy and paste the release notes from the blog into the email and reformat appropriately (see past emails).
+10. Post it to the LinkedIn eXist-db group: https://www.linkedin.com/groups/35624
-8. Tweet about it using the `existdb` twitter account.
+11. Submit a news item to XML.com - https://www.xml.com/news/submit-news-item/.
-9. Submit a news item to XML.com - https://www.xml.com/news/submit-news-item/.
+12. Update the Wikipedia page with the new version details - https://en.wikipedia.org/wiki/EXist.
-10. Go to GitHub and move all issues and PRs which are still open for the release milestone to the next release milestone. Close the release milestone.
+13. Go to GitHub and move all issues and PRs which are still open for the release milestone to the next release milestone. Close the release milestone.
### Preparing a Patch Release
diff --git a/extensions/betterform/README.md b/extensions/betterform/README.md
new file mode 100644
index 00000000000..712ef211814
--- /dev/null
+++ b/extensions/betterform/README.md
@@ -0,0 +1,29 @@
+# betterFORM eXist-db Integration
+
+Since eXist-db 5.0.0, the full betterFORM XForms package is no longer enabled by default, instead just the `ResourceServlet` is present (as this is needed by eXide and a bunch of other apps).
+
+
+## Install Instructions
+
+By default only the betterForm ResourceServlet is installed. If you want the full betterForm XForms experience, then:
+
+1. Stop eXist-db (if it is running).
+
+2. Set the property `include.feature.betterform` in your `$EXIST_HOME/extensions/local.build.properties` file. See `$EXIST_HOME/extensions/build.properties` for details.
+
+3. `cd $EXIST_HOME/extensions/betterform`.
+
+4. Run the following: `../../build.sh install` (or you can use `..\..\build.bat install` if you are on Windows).
+
+5. Start eXist-db.
+
+
+## Uninstall Instructions
+
+1. Stop eXist-db (if it is running).
+
+2. `cd $EXIST_HOME/extensions/betterform`.
+
+3. Run the following: `../../build.sh clean` (or you can use `..\..\build.bat clean` if you are on Windows).
+
+4. Start eXist-db.
diff --git a/extensions/betterform/build.xml b/extensions/betterform/build.xml
index 982468e9f1f..30ca6d804a4 100644
--- a/extensions/betterform/build.xml
+++ b/extensions/betterform/build.xml
@@ -1,53 +1,48 @@
-
-
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
- XSLT Generating @{out}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
@@ -55,77 +50,104 @@
-
-
- Add betterFORM config parameters to eXist to ${exist.web.xml}
-
+
-
+
-
- Deploy betterFORM resources to eXist webapp (${exist.rootdir}/webapp/WEB-INF/)
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- Uninstalling betterFORM.
-
+
-
-
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
- Creating uninstall folder.
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
- Copying betterFORM configuration files to WEB-INF dir.
-
-
-
-
-
-
-
-
-
diff --git a/extensions/betterform/main/etc/MergeWebXML.xsl b/extensions/betterform/main/etc/MergeWebXML.xsl
index 683505aecad..943616a00d6 100644
--- a/extensions/betterform/main/etc/MergeWebXML.xsl
+++ b/extensions/betterform/main/etc/MergeWebXML.xsl
@@ -1,44 +1,114 @@
-
+ exclude-result-prefixes="webxml xs"
+ version="2.0">
-
+
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
- ====================== betterFORM configuration file ======================
-
-
-
+
+
+
+
+ betterFORM configuration file
+
+ betterform.configfileWEB-INF/betterform-config.xml
-
-
-
-
- ====================== betterFORM filter and servlets ======================
-
-
- ====================== betterFORM servlets ======================
-
-
+
+
+
+
+
+
+
+
+
+ betterFORM servlets
+
+
+
+
+
+
+
+
+
+
+
+
+
+ betterFORM servlet mappings
+
+
+
+
+
+
+
+
+
+
+
+ betterFORM filter
+
+
+
+
+
+
+ betterFORM filter mappings
+
+
+
+
+
+
+
+
+
+
+
+
+ ResourceServlet
+ de.betterform.agent.web.resources.ResourceServlet
+
+ caching
+ true
+
+
+
+
+
+
+ ResourceServlet
+ /bfResources/*
+
+
+
+ Fluxorg.directwebremoting.servlet.DwrServlet
@@ -59,24 +129,13 @@
inspectorde.betterform.agent.web.servlet.XFormsInspectorServlet
-
- ResourceServlet
- de.betterform.agent.web.resources.ResourceServlet
-
- caching
- true
-
- errorde.betterform.agent.web.servlet.ErrorServlet
-
-
-
- ====================== betterFORM servlets mapping ======================
-
-
+
+
+ Flux/Flux/*
@@ -97,30 +156,20 @@
inspector/inspector/*
-
- ResourceServlet
- /bfResources/*
- error/error/*
-
-
-
- ====================== betterFORM filter ======================
-
-
+
+
+ XFormsFilterde.betterform.agent.web.filter.XFormsFilter
-
-
-
- ====================== betterFORM filter mapping ======================
-
-
+
+
+ XFormsFilter/apps/*
@@ -129,21 +178,31 @@
XFormsFilterXFormsPostServlet
-
-
+
de.betterform.agent.web.servlet.BfServletContextListener
-
-
- ====================== betterFORM filter and servlets ======================
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/extensions/build.properties b/extensions/build.properties
index 6158f2589a8..e4c37acd577 100644
--- a/extensions/build.properties
+++ b/extensions/build.properties
@@ -15,7 +15,11 @@
## Features
# betterFORM XForms engine
-include.feature.betterform = true
+# Valid options are:
+# 1. true betterForm will be compiled and deployed into eXist-db (will downgrade the version of Saxon to Saxon HE 9.6.0-7)
+# 2. false No betterForm components will be compiled
+# 3. resourceServlet betterForm will be compiled but only the betterForm ResourceServlet will be deployed
+include.feature.betterform = resourceServlet
# EXQuery RESTXQ
include.feature.exquery.restxq = true
diff --git a/extensions/debuggee/src/org/exist/debuggee/DebuggeeJointImpl.java b/extensions/debuggee/src/org/exist/debuggee/DebuggeeJointImpl.java
index 3710d7957fe..0d68ac4a38e 100644
--- a/extensions/debuggee/src/org/exist/debuggee/DebuggeeJointImpl.java
+++ b/extensions/debuggee/src/org/exist/debuggee/DebuggeeJointImpl.java
@@ -62,8 +62,8 @@ public class DebuggeeJointImpl implements DebuggeeJoint, Status {
private int stackDepth = 0;
private CommandContinuation command = null;
- private Stack commands = new Stack();
-
+ private Deque commands = new ArrayDeque();
+
private int breakpointNo = 0;
//>
private Map> filesBreakpoints =
@@ -77,9 +77,6 @@ public class DebuggeeJointImpl implements DebuggeeJoint, Status {
private CompiledXQuery compiledXQuery;
private boolean inProlog = false;
-
- public DebuggeeJointImpl() {
- }
protected void setCompiledScript(CompiledXQuery compiledXQuery) {
this.compiledXQuery = compiledXQuery;
@@ -246,7 +243,7 @@ public void expressionEnd(Expression expr) {
}
private synchronized void waitCommand() {
- if (commands.size() != 0 && command.isStatus(BREAK)) {
+ if (!commands.isEmpty() && command.isStatus(BREAK)) {
command = commands.pop();
((AbstractCommandContinuation)command).setCallStackDepth(stackDepth);
@@ -297,7 +294,7 @@ public synchronized void continuation(CommandContinuation command) {
this.command = command;
} else {
- commands.add(command);
+ commands.push(command);
}
notifyAll();
diff --git a/extensions/debuggee/src/org/exist/debuggee/ScriptRunner.java b/extensions/debuggee/src/org/exist/debuggee/ScriptRunner.java
index 5293327d396..c7bf7e62786 100644
--- a/extensions/debuggee/src/org/exist/debuggee/ScriptRunner.java
+++ b/extensions/debuggee/src/org/exist/debuggee/ScriptRunner.java
@@ -31,6 +31,8 @@
import org.exist.xquery.CompiledXQuery;
import org.exist.xquery.XQuery;
+import static org.exist.util.ThreadUtils.nameInstanceThread;
+
/**
* @author Dmitriy Shabanov
*
@@ -48,7 +50,7 @@ public ScriptRunner(SessionImpl session, CompiledXQuery compiled) {
this.session = session;
expression = compiled;
- thread = new Thread(this);
+ thread = newInstanceThread(BrokerPool.getInstance(), "scriptRunner" this);
thread.setDaemon(true);
thread.setName("Debug session "+compiled.getContext().hashCode());
}
diff --git a/extensions/debuggee/src/org/exist/debuggee/dbgp/packets/Command.java b/extensions/debuggee/src/org/exist/debuggee/dbgp/packets/Command.java
index 62a318976b3..c8e2d65f40c 100644
--- a/extensions/debuggee/src/org/exist/debuggee/dbgp/packets/Command.java
+++ b/extensions/debuggee/src/org/exist/debuggee/dbgp/packets/Command.java
@@ -194,7 +194,7 @@ public static Command parse(IoSession session, String message) {
public static String getFileuri(org.exist.source.Source fileuri) {
// System.out.println("getFileuri dbgp:"+fileuri.getType()+"://"+fileuri.getKey());
- if (fileuri.type().toLowerCase().equals("file")) {
+ if (fileuri.type().equalsIgnoreCase("file")) {
try {
return new java.io.File(fileuri.path()).toURI().toURL().toString();
} catch (MalformedURLException e) {
diff --git a/extensions/debuggee/src/org/exist/debuggee/dbgp/packets/Source.java b/extensions/debuggee/src/org/exist/debuggee/dbgp/packets/Source.java
index 88dc47fff97..51c04f7e229 100644
--- a/extensions/debuggee/src/org/exist/debuggee/dbgp/packets/Source.java
+++ b/extensions/debuggee/src/org/exist/debuggee/dbgp/packets/Source.java
@@ -27,6 +27,7 @@
import org.exist.debuggee.dbgp.Errors;
import org.exist.dom.persistent.BinaryDocument;
import org.exist.dom.persistent.DocumentImpl;
+import org.exist.dom.persistent.LockedDocument;
import org.exist.security.PermissionDeniedException;
import org.exist.storage.DBBroker;
import org.exist.storage.lock.Lock.LockMode;
@@ -96,7 +97,6 @@ public void exec() {
return;
}
- DocumentImpl resource = null;
InputStream is = null;
try {
@@ -109,11 +109,11 @@ public void exec() {
XmldbURI pathUri = XmldbURI.create( URLDecoder.decode( fileURI.substring(15) , "UTF-8" ) );
Database db = getJoint().getContext().getDatabase();
- try(final DBBroker broker = db.getBroker()) {
- resource = broker.getXMLResource(pathUri, LockMode.READ_LOCK);
+ try(final DBBroker broker = db.getBroker();
+ final LockedDocument resource = broker.getXMLResource(pathUri, LockMode.READ_LOCK)) {
- if (resource.getResourceType() == DocumentImpl.BINARY_FILE) {
- is = broker.getBinaryResource((BinaryDocument) resource);
+ if (resource.getDocument().getResourceType() == DocumentImpl.BINARY_FILE) {
+ is = broker.getBinaryResource((BinaryDocument) resource.getDocument());
} else {
//TODO: xml source???
return;
@@ -150,10 +150,6 @@ public void exec() {
}
}
}
-
- if(resource != null) {
- resource.getUpdateLock().release(LockMode.READ_LOCK);
- }
}
}
diff --git a/extensions/debuggee/src/org/exist/debugger/DebuggerImpl.java b/extensions/debuggee/src/org/exist/debugger/DebuggerImpl.java
index 727f30eb2e7..6597d9016f5 100644
--- a/extensions/debuggee/src/org/exist/debugger/DebuggerImpl.java
+++ b/extensions/debuggee/src/org/exist/debugger/DebuggerImpl.java
@@ -50,6 +50,8 @@
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
+import static org.exist.util.ThreadUtils.newGlobalThread;
+
/**
* @author Dmitriy Shabanov
*
@@ -117,7 +119,7 @@ public DebuggingSource init(String url) throws IOException,
sources = new HashMap();
currentTransactionId = 1;
- Thread session = new Thread(new HttpSession(this, url));
+ Thread session = newGlobalThread("debuggerHttpSession" new HttpSession(this, url));
session.start();
// 30s timeout
diff --git a/extensions/debuggee/src/org/exist/debugger/dbgp/CodecFactory.java b/extensions/debuggee/src/org/exist/debugger/dbgp/CodecFactory.java
index c9b2a27a4ab..28f023432d9 100644
--- a/extensions/debuggee/src/org/exist/debugger/dbgp/CodecFactory.java
+++ b/extensions/debuggee/src/org/exist/debugger/dbgp/CodecFactory.java
@@ -37,9 +37,6 @@ public class CodecFactory implements ProtocolCodecFactory {
private Map encoders = new HashMap();
private Map decoders = new HashMap();
-
- public CodecFactory() {
- }
public ProtocolDecoder getDecoder(IoSession ioSession) throws Exception {
synchronized (decoders) {//TODO: rewrite???
diff --git a/extensions/debuggee/test/org/exist/debugger/DebuggerTest.java b/extensions/debuggee/test/org/exist/debugger/DebuggerTest.java
index 6af31dcb10d..1db125f4b4a 100644
--- a/extensions/debuggee/test/org/exist/debugger/DebuggerTest.java
+++ b/extensions/debuggee/test/org/exist/debugger/DebuggerTest.java
@@ -358,7 +358,7 @@ public void testResourceNotExistOrNotRunnable() throws IOException {
// jetty.port.jetty
debugger.init("http://127.0.0.1:" + System.getProperty("jetty.port") + "/exist/logo.jpg");
- assertTrue("This point should not be reached", false);
+ fail("This point should not be reached");
} catch (IOException e) {
exception = e;
@@ -372,7 +372,7 @@ public void testResourceNotExistOrNotRunnable() throws IOException {
// jetty.port.jetty
debugger.init("http://127.0.0.1:" + System.getProperty("jetty.port") + "/notExist/fibo.xql");
- assertTrue("This point should not be reached", false);
+ fail("This point should not be reached");
} catch (IOException e) {
exception = e;
diff --git a/extensions/exiftool/src/org/exist/exiftool/xquery/MetadataFunctions.java b/extensions/exiftool/src/org/exist/exiftool/xquery/MetadataFunctions.java
index b8e63bee8fb..7215a38ca98 100644
--- a/extensions/exiftool/src/org/exist/exiftool/xquery/MetadataFunctions.java
+++ b/extensions/exiftool/src/org/exist/exiftool/xquery/MetadataFunctions.java
@@ -12,6 +12,7 @@
import org.exist.dom.persistent.BinaryDocument;
import org.exist.dom.persistent.DocumentImpl;
import org.exist.dom.QName;
+import org.exist.dom.persistent.LockedDocument;
import org.exist.security.PermissionDeniedException;
import org.exist.source.Source;
import org.exist.source.SourceFactory;
@@ -90,11 +91,10 @@ public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathExce
}
- private Sequence extractMetadataFromLocalResource(XmldbURI docUri) throws XPathException {
- DocumentImpl doc = null;
- try {
- doc = context.getBroker().getXMLResource(docUri, LockMode.READ_LOCK);
- if (doc instanceof BinaryDocument) {
+ private Sequence extractMetadataFromLocalResource(final XmldbURI docUri) throws XPathException {
+ try(final LockedDocument lockedDoc = context.getBroker().getXMLResource(docUri, LockMode.READ_LOCK)) {
+
+ if (lockedDoc != null && lockedDoc.getDocument() instanceof BinaryDocument) {
//resolve real filesystem path of binary file
final Path binaryFile = ((NativeBroker) context.getBroker()).getCollectionBinaryFileFsPath(docUri);
if (!Files.exists(binaryFile)) {
@@ -106,10 +106,6 @@ private Sequence extractMetadataFromLocalResource(XmldbURI docUri) throws XPathE
}
} catch (PermissionDeniedException pde) {
throw new XPathException("Could not access binary document: " + pde.getMessage(), pde);
- } finally {
- if (doc != null) {
- doc.getUpdateLock().release(LockMode.READ_LOCK);
- }
}
}
@@ -159,6 +155,9 @@ private Sequence exifToolWebExtract(final URI uri) throws XPathException {
try(final OutputStream stdOut = p.getOutputStream()) {
final Source src = SourceFactory.getSource(context.getBroker(), null, uri.toString(), false);
+ if (src == null) {
+ throw new XPathException("Could not read source for the Exiftool: " + uri.toString());
+ }
try(final InputStream isSrc = src.getInputStream()) {
//write the remote data to stdOut
diff --git a/extensions/expath/lib/http-client-java-1.0-SNAPSHOT.jar b/extensions/expath/lib/http-client-java-1.0-SNAPSHOT.jar
index be0d8afdb6f..aea03b9404e 100644
Binary files a/extensions/expath/lib/http-client-java-1.0-SNAPSHOT.jar and b/extensions/expath/lib/http-client-java-1.0-SNAPSHOT.jar differ
diff --git a/extensions/expath/src/org/expath/exist/SendRequestFunction.java b/extensions/expath/src/org/expath/exist/SendRequestFunction.java
index 3a8302b4109..129a06920d4 100644
--- a/extensions/expath/src/org/expath/exist/SendRequestFunction.java
+++ b/extensions/expath/src/org/expath/exist/SendRequestFunction.java
@@ -23,7 +23,6 @@
import java.net.URI;
import java.net.URISyntaxException;
-
import org.apache.http.HttpStatus;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -170,7 +169,7 @@ private EXistResult sendOnce(final URI uri, final HttpRequest request, final Req
HttpConnection conn = null;
try {
conn = new ApacheHttpConnection(uri);
- final HttpResponse response = request.send(result, conn, parser.getSendAuth() ? parser.getCredentials() : null);
+ final HttpResponse response = request.send(result, conn, parser.getCredentials());
if(response.getStatus() == HttpStatus.SC_UNAUTHORIZED && parser.getCredentials() != null) {
// requires authorization, try again with auth
result = new EXistResult(getContext());
diff --git a/extensions/expath/src/org/expath/exist/ZipEntryFunctions.java b/extensions/expath/src/org/expath/exist/ZipEntryFunctions.java
index 21eb96c6f11..418a241ccab 100644
--- a/extensions/expath/src/org/expath/exist/ZipEntryFunctions.java
+++ b/extensions/expath/src/org/expath/exist/ZipEntryFunctions.java
@@ -26,6 +26,7 @@
import java.io.Reader;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
+import javax.annotation.Nullable;
import javax.xml.transform.stream.StreamSource;
import org.apache.logging.log4j.LogManager;
@@ -33,6 +34,7 @@
import org.exist.dom.persistent.BinaryDocument;
import org.exist.dom.QName;
import org.exist.dom.persistent.DocumentImpl;
+import org.exist.dom.persistent.LockedDocument;
import org.exist.security.PermissionDeniedException;
import org.exist.storage.DBBroker;
import org.exist.storage.lock.Lock.LockMode;
@@ -222,7 +224,7 @@ public interface ZipFileSource extends AutoCloseable {
}
protected static class ZipFileFromDb implements ZipFileSource {
- private BinaryDocument binaryDoc = null;
+ private LockedDocument binaryDoc = null;
private final XmldbURI uri;
public ZipFileFromDb(final XmldbURI uri) {
@@ -235,26 +237,30 @@ public ZipInputStream getStream(final DBBroker broker) throws IOException, Permi
binaryDoc = getDoc(broker);
}
- return new ZipInputStream(broker.getBinaryResource(binaryDoc));
+ return new ZipInputStream(broker.getBinaryResource((BinaryDocument)binaryDoc.getDocument()));
}
@Override
public void close() {
if (binaryDoc != null) {
- binaryDoc.getUpdateLock().release(LockMode.READ_LOCK);
+ binaryDoc.close();
}
}
- private BinaryDocument getDoc(final DBBroker broker) throws PermissionDeniedException {
- final DocumentImpl doc = broker.getXMLResource(uri, LockMode.READ_LOCK);
- if (doc == null) {
+ /**
+ * @return only binary document otherwise null
+ */
+ @Nullable
+ private LockedDocument getDoc(final DBBroker broker) throws PermissionDeniedException {
+ final LockedDocument lockedDoc = broker.getXMLResource(uri, LockMode.READ_LOCK);
+ if(lockedDoc == null) {
return null;
- } else if (doc.getResourceType() != DocumentImpl.BINARY_FILE) {
- doc.getUpdateLock().release(LockMode.READ_LOCK);
+ } else if (lockedDoc.getDocument().getResourceType() != DocumentImpl.BINARY_FILE) {
+ lockedDoc.close();
return null;
}
- return (BinaryDocument) doc;
+ return lockedDoc;
}
}
}
\ No newline at end of file
diff --git a/extensions/expath/src/org/expath/exist/ZipFileFunctions.java b/extensions/expath/src/org/expath/exist/ZipFileFunctions.java
index a57206fb546..a294c0840e6 100644
--- a/extensions/expath/src/org/expath/exist/ZipFileFunctions.java
+++ b/extensions/expath/src/org/expath/exist/ZipFileFunctions.java
@@ -6,6 +6,7 @@
import org.exist.dom.QName;
import org.exist.dom.persistent.DocumentImpl;
import org.exist.dom.memtree.MemTreeBuilder;
+import org.exist.dom.persistent.LockedDocument;
import org.exist.security.PermissionDeniedException;
import org.exist.util.io.FastByteArrayOutputStream;
import org.exist.xmldb.XmldbURI;
@@ -232,13 +233,12 @@ private Sequence createZip(Element zipFile) {
// copied from
public interface ZipFileSource {
- public ZipInputStream getStream() throws IOException, PermissionDeniedException;
-
- public void close();
+ ZipInputStream getStream() throws IOException, PermissionDeniedException;
+ void close();
}
private class ZipFileFromDb implements ZipFileSource {
- private BinaryDocument binaryDoc = null;
+ private LockedDocument binaryDoc = null;
private final XmldbURI uri;
public ZipFileFromDb(XmldbURI uri) {
@@ -247,33 +247,32 @@ public ZipFileFromDb(XmldbURI uri) {
@Override
public ZipInputStream getStream() throws IOException, PermissionDeniedException {
-
if (binaryDoc == null) {
binaryDoc = getBinaryDoc();
}
- return new ZipInputStream(context.getBroker().getBinaryResource(binaryDoc));
+ return new ZipInputStream(context.getBroker().getBinaryResource((BinaryDocument)binaryDoc.getDocument()));
}
@Override
public void close() {
if (binaryDoc != null) {
- binaryDoc.getUpdateLock().release(LockMode.READ_LOCK);
+ binaryDoc.close();
}
}
- private BinaryDocument getBinaryDoc() throws PermissionDeniedException {
- final DocumentImpl doc = context.getBroker().getXMLResource(uri, LockMode.READ_LOCK);
- if (doc == null) {
+ private LockedDocument getBinaryDoc() throws PermissionDeniedException {
+ final LockedDocument lockedDocment = context.getBroker().getXMLResource(uri, LockMode.READ_LOCK);
+ if (lockedDocment == null) {
return null;
}
- if(doc.getResourceType() != DocumentImpl.BINARY_FILE) {
- doc.getUpdateLock().release(LockMode.READ_LOCK);
+ if(lockedDocment.getDocument().getResourceType() != DocumentImpl.BINARY_FILE) {
+ lockedDocment.close();
return null;
}
- return (BinaryDocument) doc;
+ return lockedDocment;
}
}
diff --git a/extensions/expath/src/org/expath/tools/model/exist/EXistAttribute.java b/extensions/expath/src/org/expath/tools/model/exist/EXistAttribute.java
index 8cad1450996..8d89d5c6c55 100644
--- a/extensions/expath/src/org/expath/tools/model/exist/EXistAttribute.java
+++ b/extensions/expath/src/org/expath/tools/model/exist/EXistAttribute.java
@@ -53,7 +53,7 @@ public String getValue() {
@Override
public boolean getBoolean() throws ToolsException {
- return attribute.getValue().toLowerCase().equals("true");
+ return attribute.getValue().equalsIgnoreCase("true");
}
@Override
diff --git a/extensions/exquery/restxq/src/main/java/org/exist/extensions/exquery/restxq/impl/RestXqServiceCompiledXQueryCacheImpl.java b/extensions/exquery/restxq/src/main/java/org/exist/extensions/exquery/restxq/impl/RestXqServiceCompiledXQueryCacheImpl.java
index 78db3e75fa2..88824a42ab1 100644
--- a/extensions/exquery/restxq/src/main/java/org/exist/extensions/exquery/restxq/impl/RestXqServiceCompiledXQueryCacheImpl.java
+++ b/extensions/exquery/restxq/src/main/java/org/exist/extensions/exquery/restxq/impl/RestXqServiceCompiledXQueryCacheImpl.java
@@ -36,6 +36,7 @@
import org.exist.extensions.exquery.restxq.RestXqServiceCompiledXQueryCache;
import org.exist.storage.DBBroker;
import org.exist.xquery.CompiledXQuery;
+import org.exist.xquery.XPathException;
import org.exquery.restxq.RestXqService;
import org.exquery.restxq.RestXqServiceException;
import org.jctools.queues.atomic.MpmcAtomicArrayQueue;
@@ -75,11 +76,14 @@ public CompiledXQuery getCompiledQuery(final DBBroker broker, final URI xqueryLo
CompiledXQuery xquery = queue.poll();
if(xquery == null) {
xquery = XQueryCompiler.compile(broker, xqueryLocation);
+ } else {
+ // prepare the context for re-use
+ try {
+ xquery.getContext().prepareForReuse();
+ } catch (final XPathException e) {
+ throw new RestXqServiceException("Unable to prepare compiled XQuery for reuse", e);
+ }
}
-
- //reset the state of the query
- xquery.reset();
- xquery.getContext().getWatchDog().reset();
xquery.getContext().prepareForExecution();
return xquery;
@@ -140,4 +144,4 @@ public U next() {
}
};
}
-}
\ No newline at end of file
+}
diff --git a/extensions/exquery/restxq/src/main/java/org/exist/extensions/exquery/restxq/impl/RestXqStartupTrigger.java b/extensions/exquery/restxq/src/main/java/org/exist/extensions/exquery/restxq/impl/RestXqStartupTrigger.java
index 00114e66927..ff8ad333cd5 100644
--- a/extensions/exquery/restxq/src/main/java/org/exist/extensions/exquery/restxq/impl/RestXqStartupTrigger.java
+++ b/extensions/exquery/restxq/src/main/java/org/exist/extensions/exquery/restxq/impl/RestXqStartupTrigger.java
@@ -30,6 +30,7 @@
import java.util.Map;
import org.exist.storage.DBBroker;
import org.exist.storage.StartupTrigger;
+import org.exist.storage.txn.Txn;
/**
* Loads the RESTXQ Registry from disk during database startup
@@ -41,7 +42,7 @@
public class RestXqStartupTrigger implements StartupTrigger {
@Override
- public void execute(final DBBroker broker, final Map> params) {
+ public void execute(final DBBroker broker, final Txn transaction, final Map> params) {
RestXqServiceRegistryManager.getRegistry(broker.getBrokerPool());
}
-}
\ No newline at end of file
+}
diff --git a/extensions/fluent/src/org/exist/fluent/Database.java b/extensions/fluent/src/org/exist/fluent/Database.java
index 2f4954c43f3..b8b7dac274b 100644
--- a/extensions/fluent/src/org/exist/fluent/Database.java
+++ b/extensions/fluent/src/org/exist/fluent/Database.java
@@ -15,8 +15,9 @@
import org.exist.dom.persistent.TextImpl;
import org.exist.security.*;
import org.exist.storage.*;
-import org.exist.storage.lock.Lock;
import org.exist.storage.lock.Lock.LockMode;
+import org.exist.storage.lock.LockManager;
+import org.exist.storage.lock.ManagedDocumentLock;
import org.exist.storage.sync.Sync;
import org.exist.storage.txn.TransactionManager;
import org.exist.util.*;
@@ -29,6 +30,8 @@
import java.text.MessageFormat;
import java.util.*;
+import static org.exist.util.ThreadUtils.newInstanceThread;
+
/**
*
The global entry point to an embedded instance of the eXist database.
* The static methods on this class control the lifecycle of the database connection. It follows that
@@ -70,6 +73,7 @@ public static void startup(Path configFile) {
BrokerPool.configure(dbName, 1, 5, config);
pool = BrokerPool.getInstance(dbName);
txManager = pool.getTransactionManager();
+ lockManager = pool.getLockManager();
configureRootCollection(configFile);
defragmenter.start();
QueryService.statistics().reset();
@@ -104,20 +108,17 @@ static void configureRootCollection(Path configFile) {
}
// Now force reload and reindex so it'll pick up the new settings.
- Transaction tx = db.requireTransactionWithBroker();
try {
- pool.getConfigurationManager().addConfiguration(tx.tx, tx.broker, tx.broker.getCollection(XmldbURI.ROOT_COLLECTION_URI), configXml.toString());
- tx.commit();
- DBBroker broker = db.acquireBroker();
- try {
- broker.reindexCollection(XmldbURI.ROOT_COLLECTION_URI);
- } finally {
- db.releaseBroker(broker);
+ try(final Transaction tx = db.requireTransactionWithBroker()) {
+ pool.getConfigurationManager().addConfiguration(tx.tx, tx.broker, tx.broker.getCollection(XmldbURI.ROOT_COLLECTION_URI), configXml.toString());
+ tx.commit();
+ }
+ try(final Transaction tx = db.requireTransactionWithBroker()) {
+ tx.broker.reindexCollection(tx.tx, XmldbURI.ROOT_COLLECTION_URI);
+ tx.commit();
}
- } catch (final PermissionDeniedException | IOException | CollectionConfigurationException e) {
+ } catch (final PermissionDeniedException | IOException | LockException | CollectionConfigurationException e) {
throw new DatabaseException(e);
- } finally {
- tx.abortIfIncomplete();
}
}
@@ -246,6 +247,7 @@ public static Database current() throws DatabaseException {
try {
pool = BrokerPool.getInstance(dbName);
txManager = pool.getTransactionManager();
+ lockManager = pool.getLockManager();
//configureRootCollection(configFile);
//defragmenter.start();
//QueryService.statistics().reset();
@@ -283,6 +285,7 @@ static String normalizePath(String path) {
public static final String ROOT_PREFIX = XmldbURI.ROOT_COLLECTION;
private static volatile BrokerPool pool;
private static TransactionManager txManager;
+ private static LockManager lockManager;
private static final ThreadLocal localTransaction = new ThreadLocal();
private static final WeakHashMap instrumentedBrokers = new WeakHashMap();
@@ -383,9 +386,10 @@ public boolean contains(String path) {
if (broker.getCollection(XmldbURI.create(path)) != null) return true;
String folderPath = path.substring(0, i);
String name = path.substring(i+1);
- Collection collection = broker.openCollection(XmldbURI.create(folderPath), LockMode.NO_LOCK);
- if (collection == null) return false;
- return collection.getDocument(broker, XmldbURI.create(name)) != null;
+ try(final Collection collection = broker.openCollection(XmldbURI.create(folderPath), LockMode.NO_LOCK)) {
+ if (collection == null) return false;
+ return collection.getDocument(broker, XmldbURI.create(name)) != null;
+ }
} catch(PermissionDeniedException pde) {
throw new DatabaseException(pde.getMessage(), pde);
} finally {
@@ -485,12 +489,18 @@ public QueryService query(final java.util.Collection extends Resource> context
*/
static Transaction requireTransaction() {
Transaction t = localTransaction.get();
- return t == null ? new Transaction(txManager, null) : new Transaction(t, null);
+ return t == null ? new Transaction(txManager, lockManager, null) : new Transaction(txManager, t, lockManager, null);
}
Transaction requireTransactionWithBroker() {
Transaction t = localTransaction.get();
- return t == null ? new Transaction(txManager, this) : new Transaction(t, this);
+ if (t == null) {
+ try (final DBBroker broker = acquireBroker()) {
+ return new Transaction(txManager, broker.getCurrentTransaction(), lockManager, this);
+ }
+ } else {
+ return new Transaction(txManager, t, lockManager, this);
+ }
}
void checkSame(Resource o) {
@@ -553,7 +563,7 @@ private static class Defragmenter implements Runnable {
public void start() {
if (thread != null) return;
- thread = new Thread(this, "Database defragmenter");
+ thread = newInstanceThread(pool, "fluent.database-defragmenter", this);
thread.setPriority(Thread.NORM_PRIORITY-3);
thread.setDaemon(true);
thread.start();
@@ -604,22 +614,19 @@ public void run() {
it.remove();
} else {
// Must hold write lock on doc before checking stale map to avoid race condition
- if (doc.getUpdateLock().attempt(LockMode.WRITE_LOCK)) try {
+ try(final ManagedDocumentLock updateLock = pool.getLockManager().acquireDocumentWriteLock(doc.getURI())) {
String docPath = normalizePath(doc.getURI().getCollectionPath());
if (!staleMap.containsKey(docPath)) {
LOG.debug("defragmenting " + docPath);
count++;
- Transaction tx = Database.requireTransaction();
- try {
+ try(final Transaction tx = Database.requireTransaction()) {
broker.defragXMLResource(tx.tx, doc);
tx.commit();
it.remove();
- } finally {
- tx.abortIfIncomplete();
}
}
- } finally {
- doc.getUpdateLock().release(LockMode.WRITE_LOCK);
+ } catch(final LockException e) {
+ // not a problem, we only attempted the lock!
}
}
}
diff --git a/extensions/fluent/src/org/exist/fluent/Document.java b/extensions/fluent/src/org/exist/fluent/Document.java
index 2d908d51dc2..1aead899e02 100644
--- a/extensions/fluent/src/org/exist/fluent/Document.java
+++ b/extensions/fluent/src/org/exist/fluent/Document.java
@@ -127,9 +127,9 @@ public void remove(Document.Listener listener) {
*/
public static class MetadataFacet extends NamedResource.MetadataFacet {
private final DocumentMetadata docMetadata;
- private MetadataFacet(Permission permissions, DocumentMetadata docMetadata, Database db) {
- super(permissions, db);
- this.docMetadata = docMetadata;
+ private MetadataFacet(final DocumentImpl doc, final Database db) {
+ super(doc, db);
+ this.docMetadata = doc.getMetadata();
}
@Override public Date creationDate() {return new Date(docMetadata.getCreated());}
@@ -199,7 +199,7 @@ public ListenersFacet listeners() {
}
@Override public MetadataFacet metadata() {
- if (metadata == null) metadata = new MetadataFacet(doc.getPermissions(), doc.getMetadata(), db);
+ if (metadata == null) metadata = new MetadataFacet(doc, db);
return metadata;
}
diff --git a/extensions/fluent/src/org/exist/fluent/Folder.java b/extensions/fluent/src/org/exist/fluent/Folder.java
index de40bf32715..d49d6c2166a 100644
--- a/extensions/fluent/src/org/exist/fluent/Folder.java
+++ b/extensions/fluent/src/org/exist/fluent/Folder.java
@@ -15,7 +15,6 @@
import org.exist.collections.triggers.TriggerException;
import org.exist.security.PermissionDeniedException;
import org.exist.storage.DBBroker;
-import org.exist.storage.lock.Lock;
import org.exist.storage.lock.Lock.LockMode;
import org.exist.util.LockException;
import org.exist.xmldb.XmldbURI;
@@ -312,6 +311,38 @@ public void remove(Document.Listener listener) {
}
}
+ public class DocumentsFacetIterator implements Iterator {
+ private Iterator delegate;
+ private Document last;
+
+ public DocumentsFacetIterator() {
+ acquire(LockMode.READ_LOCK);
+ try {
+ delegate = handle.iterator(broker);
+ } catch(PermissionDeniedException | LockException e) {
+ throw new DatabaseException(e.getMessage(), e);
+ } finally {
+ release();
+ }
+ }
+
+ public void remove() {
+ staleMarker.check();
+ if (last == null) throw new IllegalStateException("no document to remove");
+ last.delete();
+ last = null;
+ }
+ public boolean hasNext() {
+ staleMarker.check();
+ return delegate.hasNext();
+ }
+ public Document next() {
+ staleMarker.check();
+ last = Document.newInstance(delegate.next(), Folder.this);
+ return last;
+ }
+ }
+
private DocumentsFacet() {
super(Folder.this.namespaceBindings, Folder.this.db);
}
@@ -351,7 +382,7 @@ public XMLDocument completed(Node[] nodes) {
try {
name.setContext(handle);
IndexInfo info = handle.validateXMLResource(tx.tx, broker, XmldbURI.create(name.get()), node);
- changeLock(LockMode.NO_LOCK);
+ //changeLock(LockMode.NO_LOCK);
handle.store(tx.tx, broker, info, node);
commit();
} catch (EXistException e) {
@@ -415,7 +446,7 @@ public XMLDocument load(Name name, Source.XML source) {
source.applyOldName(name);
name.setContext(handle);
IndexInfo info = handle.validateXMLResource(tx.tx, broker, XmldbURI.create(name.get()), source.toInputSource());
- changeLock(LockMode.NO_LOCK);
+ //changeLock(LockMode.NO_LOCK);
handle.store(tx.tx, broker, info, source.toInputSource());
commit();
} catch (EXistException e) {
@@ -558,8 +589,8 @@ protected void prepareContext(DBBroker broker_) {
try {
docs = handle.allDocs(broker_, new DefaultDocumentSet(), false);
baseUri = new AnyURIValue(handle.getURI());
- }catch (PermissionDeniedException pde) {
- throw new DatabaseException(pde.getMessage(), pde);
+ } catch (final PermissionDeniedException | LockException e) {
+ throw new DatabaseException(e.getMessage(), e);
} finally {
release();
}
@@ -573,38 +604,10 @@ protected void prepareContext(DBBroker broker_) {
*
* @return an iterator over the folder's immediate documents
*/
+ @Override
public Iterator iterator() {
- return new Iterator() {
- private Iterator delegate;
- private Document last;
- {
- acquire(LockMode.READ_LOCK);
- try {
- delegate = handle.iterator(broker);
- } catch(PermissionDeniedException | LockException e) {
- throw new DatabaseException(e.getMessage(), e);
- } finally {
- release();
- }
- }
- public void remove() {
- staleMarker.check();
- if (last == null) throw new IllegalStateException("no document to remove");
- last.delete();
- last = null;
- }
- public boolean hasNext() {
- staleMarker.check();
- return delegate.hasNext();
- }
- public Document next() {
- staleMarker.check();
- last = Document.newInstance(delegate.next(), Folder.this);
- return last;
- }
- };
+ return new DocumentsFacetIterator();
}
-
}
/**
@@ -691,13 +694,14 @@ public void remove(org.exist.fluent.Listener listener) {
broker = db.acquireBroker();
Collection collection;
if (createIfMissing) {
- tx = Database.requireTransaction();
- try {
+
+ try{
+ tx = db.requireTransactionWithBroker();
collection = createInternal(path);
tx.commit();
} finally {
- tx.abortIfIncomplete();
- }
+ tx.close();
+ }
} else {
try {
collection = broker.getCollection(XmldbURI.create(path));
@@ -736,7 +740,7 @@ public ListenersFacet listeners() {
}
@Override public MetadataFacet metadata() {
- if (metadata == null) metadata = new MetadataFacet(getQuickHandle().getPermissionsNoLock(), db) {
+ if (metadata == null) metadata = new MetadataFacet(getQuickHandle(), db) {
@Override public Date creationDate() {
return new Date(getQuickHandle().getCreationTime());
}
@@ -795,7 +799,7 @@ private Collection createInternal(String targetPath) {
void transact(LockMode _lockMode) {
if (tx != null) throw new IllegalStateException("transaction already in progress");
- tx = Database.requireTransaction();
+ tx = db.requireTransactionWithBroker();
acquire(_lockMode);
}
@@ -838,10 +842,16 @@ void acquire(LockMode _lockMode, DBBroker _broker) {
}
void release() {
- if (broker == null || handle == null) throw new IllegalStateException("broker not acquired");
- if (tx != null) tx.abortIfIncomplete();
- if (lockMode != LockMode.NO_LOCK) handle.getLock().release(lockMode);
- if (ownBroker) db.releaseBroker(broker);
+ if (broker == null || handle == null) {
+ throw new IllegalStateException("broker not acquired");
+ }
+ if (tx != null) {
+ tx.close();
+ }
+ handle.close();
+ if (ownBroker) {
+ db.releaseBroker(broker);
+ }
ownBroker = false;
broker = null;
handle = null;
@@ -853,14 +863,23 @@ void changeLock(LockMode newLockMode) {
if (lockMode == newLockMode) return;
if (lockMode == LockMode.NO_LOCK) {
try {
- handle.getLock().acquire(newLockMode);
+ switch(newLockMode) {
+ case READ_LOCK:
+ broker.getBrokerPool().getLockManager().acquireCollectionReadLock(handle.getURI());
+ break;
+ case WRITE_LOCK:
+ broker.getBrokerPool().getLockManager().acquireCollectionWriteLock(handle.getURI());
+ break;
+ case NO_LOCK:
+ break;
+ }
lockMode = newLockMode;
} catch (LockException e) {
throw new DatabaseException(e);
}
} else {
if (newLockMode != LockMode.NO_LOCK) throw new IllegalStateException("cannot change between read and write lock modes");
- handle.getLock().release(lockMode);
+ handle.close();
lockMode = newLockMode;
}
}
@@ -1110,9 +1129,9 @@ private Sequence getDocsSequence(boolean recursive) {
acquire(LockMode.READ_LOCK);
try {
docs = handle.allDocs(broker, new DefaultDocumentSet(), recursive);
- } catch(PermissionDeniedException pde) {
- throw new DatabaseException(pde.getMessage(), pde);
- } finally {
+ } catch (final PermissionDeniedException | LockException e) {
+ throw new DatabaseException(e.getMessage(), e);
+ } finally {
release();
}
Sequence result = new ExtArrayNodeSet(docs.getDocumentCount(), 1);
@@ -1144,8 +1163,8 @@ private Sequence getDocsSequence(boolean recursive) {
try {
docs = handle.allDocs(broker_, new DefaultDocumentSet(), true);
baseUri = new AnyURIValue(handle.getURI());
- } catch(PermissionDeniedException pde) {
- throw new DatabaseException(pde.getMessage(), pde);
+ } catch (final PermissionDeniedException | LockException e) {
+ throw new DatabaseException(e.getMessage(), e);
} finally {
release();
}
@@ -1212,4 +1231,4 @@ DocumentImpl moveOrCopyDocument(DocumentImpl doc, Name name, boolean copy) {
}
-}
\ No newline at end of file
+}
diff --git a/extensions/fluent/src/org/exist/fluent/Item.java b/extensions/fluent/src/org/exist/fluent/Item.java
index 527362a98fc..4e7007373e4 100644
--- a/extensions/fluent/src/org/exist/fluent/Item.java
+++ b/extensions/fluent/src/org/exist/fluent/Item.java
@@ -52,7 +52,8 @@ public Node node() {
Item that = (Item) o;
if (this.item == that.item) return true;
if (this.item instanceof AtomicValue && that.item instanceof AtomicValue) {
- AtomicValue thisValue = (AtomicValue) this.item, thatValue = (AtomicValue) that.item;
+ AtomicValue thisValue = (AtomicValue) this.item;
+ AtomicValue thatValue = (AtomicValue) that.item;
try {
return
thisValue.getType() == thatValue.getType()
diff --git a/extensions/fluent/src/org/exist/fluent/ItemList.java b/extensions/fluent/src/org/exist/fluent/ItemList.java
index df2c0498f0d..7360d84feb6 100644
--- a/extensions/fluent/src/org/exist/fluent/ItemList.java
+++ b/extensions/fluent/src/org/exist/fluent/ItemList.java
@@ -16,7 +16,12 @@
* @version $Revision: 1.17 $ ($Date: 2006/08/14 23:18:22 $)
*/
public class ItemList extends Resource implements Iterable {
-
+
+ private Sequence seq;
+ private List items, modifiableItems;
+ private ValuesFacet values;
+ private NodesFacet nodes;
+
/**
* A facet that treats each item in the list as its effective string value. Atomic values
* are converted to strings, while nodes are converted to the concatenation of all their
@@ -194,12 +199,6 @@ public String toString() {
}
}
-
- private Sequence seq;
- private List items, modifiableItems;
- private ValuesFacet values;
- private NodesFacet nodes;
-
private ItemList() {
super(null, null);
this.seq = Sequence.EMPTY_SEQUENCE;
@@ -295,12 +294,9 @@ public Item get(int index) {
* it doesn't make sense to try to delete.
*/
public void deleteAllNodes() {
- Transaction tx = Database.requireTransaction();
- try {
+ try(final Transaction tx = db.requireTransactionWithBroker()) {
for (Item item : items) if (item instanceof Node) ((Node) item).delete();
tx.commit();
- } finally {
- tx.abortIfIncomplete();
}
}
diff --git a/extensions/fluent/src/org/exist/fluent/NamedResource.java b/extensions/fluent/src/org/exist/fluent/NamedResource.java
index dc86eca4dc5..a7befc2edae 100644
--- a/extensions/fluent/src/org/exist/fluent/NamedResource.java
+++ b/extensions/fluent/src/org/exist/fluent/NamedResource.java
@@ -5,6 +5,7 @@
import org.exist.security.Permission;
import org.exist.security.PermissionDeniedException;
+import org.exist.security.PermissionFactory;
import org.exist.storage.DBBroker;
/**
@@ -25,12 +26,12 @@ public static abstract class MetadataFacet {
Pattern.compile("(a|(u?g?o?){1,3})((=r?w?u?)|([-+](r?w?u?){1,3}))(,(a|(u?g?o?){1,3})((=r?w?u?)|([-+](r?w?u?){1,3})))*");
private static final Pattern SEGMENT_REGEX = Pattern.compile("([augo]+)([-+=])([rwu]*)");
- private Permission permissions;
- private final Database db;
+ private org.exist.Resource resource;
+ private final Database db;
- protected MetadataFacet(Permission permissions, Database db) {
- this.permissions = permissions;
- this.db = db;
+ protected MetadataFacet(final org.exist.Resource resource, final Database db) {
+ this.resource = resource;
+ this.db = db;
}
/**
@@ -45,52 +46,40 @@ protected MetadataFacet(Permission permissions, Database db) {
*
* @return the owner of this resource
*/
- public String owner() {return permissions.getOwner().getName();}
+ public String owner() {return resource.getPermissions().getOwner().getName();}
/**
* Set the owner of this resource for purposes of permission management.
*
* @param owner the new owner of this resource
*/
- public void owner(String owner) {
- DBBroker broker = null;
- try {
- broker = db.acquireBroker();
- permissions.setOwner(owner);
- } catch(PermissionDeniedException pde) {
- throw new DatabaseException(pde.getMessage(), pde);
- } finally {
- if(broker != null) {
- db.releaseBroker(broker);
- }
- }
- }
+ public void owner(final String owner) {
+ try (final DBBroker broker = db.acquireBroker()) {
+ PermissionFactory.chown(broker, resource.getPermissions(), Optional.ofNullable(owner), Optional.empty());
+ } catch (final PermissionDeniedException pde) {
+ throw new DatabaseException(pde.getMessage(), pde);
+ }
+ }
/**
* Return the group who has privileged access to this resource for purposes of permission management.
*
* @return the owning group of this resource
*/
- public String group() {return permissions.getGroup().getName();}
+ public String group() {return resource.getPermissions().getGroup().getName();}
/**
* Set the group that will have privileged access to this resource for purposes of permission management.
*
* @param group the new owning group of this resource
*/
- public void group(String group) {
- DBBroker broker = null;
- try {
- broker = db.acquireBroker();
- permissions.setGroup(group);
- } catch(PermissionDeniedException pde) {
- throw new DatabaseException(pde.getMessage(), pde);
- } finally {
- if(broker != null) {
- db.releaseBroker(broker);
- }
- }
- }
+ public void group(final String group) {
+ try (final DBBroker broker = db.acquireBroker()) {
+ PermissionFactory.chown(broker, resource.getPermissions(), Optional.empty(), Optional.ofNullable(group));
+ } catch (final PermissionDeniedException pde) {
+ throw new DatabaseException(pde.getMessage(), pde);
+ }
+ }
/**
* Return whether the given subject has the given permission. The "who" character refers to
@@ -129,10 +118,10 @@ public boolean hasPermission(final char who, final char what) {
default:
throw new IllegalArgumentException("illegal permission \"who\" code '" + who + "'");
}
- return (permissions.getMode() & mask) == mask;
+ return (resource.getPermissions().getMode() & mask) == mask;
}
- private int convertPermissionBit(char what) {
+ private int convertPermissionBit(final char what) {
switch(what) {
case Permission.READ_CHAR: return Permission.READ;
case Permission.WRITE_CHAR: return Permission.WRITE;
@@ -141,7 +130,7 @@ private int convertPermissionBit(char what) {
}
}
- private int convertPermissionBits(String what) {
+ private int convertPermissionBits(final String what) {
int perms = 0;
for (int i=0; i it = query().all(
+ for (final Iterator 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);
+ final String prefix = it.next();
+ final String namespace = it.next();
+ if (!NamespaceMap.isReservedPrefix(prefix)) {
+ namespaceMap.put(prefix, namespace);
+ }
}
return namespaceMap;
}
@@ -141,11 +144,13 @@ public NamespaceMap inScopeNamespaces() {
*/
public int compareDocumentOrderTo(Node node) {
if (this.item == node.item) return 0;
- NodeValue nv1 = (NodeValue) this.item, nv2 = (NodeValue) node.item;
+ NodeValue nv1 = (NodeValue) this.item;
+ NodeValue 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;
+ NodeProxy n1 = (NodeProxy) item;
+ NodeProxy n2 = (NodeProxy) node.item;
if (n1.getOwnerDocument().getDocId() != n2.getOwnerDocument().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;
@@ -155,7 +160,8 @@ public int compareDocumentOrderTo(Node node) {
throw new DatabaseException("unable to compare nodes", e);
}
} else if (nv1.getImplementationType() == NodeValue.IN_MEMORY_NODE) {
- org.exist.dom.memtree.NodeImpl n1 = (org.exist.dom.memtree.NodeImpl) nv1, n2 = (org.exist.dom.memtree.NodeImpl) nv2;
+ org.exist.dom.memtree.NodeImpl n1 = (org.exist.dom.memtree.NodeImpl) nv1;
+ org.exist.dom.memtree.NodeImpl n2 = (org.exist.dom.memtree.NodeImpl) nv2;
final org.exist.dom.memtree.DocumentImpl n1Doc = n1.getNodeType() == org.w3c.dom.Node.DOCUMENT_NODE ? (org.exist.dom.memtree.DocumentImpl)n1 : n1.getOwnerDocument();
final org.exist.dom.memtree.DocumentImpl n2Doc = n2.getNodeType() == org.w3c.dom.Node.DOCUMENT_NODE ? (org.exist.dom.memtree.DocumentImpl)n2 : n2.getOwnerDocument();
@@ -199,8 +205,7 @@ public ElementBuilder append() {
final StoredNode node = (StoredNode) getDOMNode();
return new ElementBuilder(namespaceBindings, true, new ElementBuilder.CompletedCallback() {
public Node completed(org.w3c.dom.Node[] nodes) {
- Transaction tx = db.requireTransactionWithBroker();
- try {
+ try(final Transaction tx = db.requireTransactionWithBroker()) {
final DocumentImpl ownerDoc = node.getOwnerDocument();
tx.lockWrite(ownerDoc);
DocumentTrigger trigger = fireTriggerBefore(tx);
@@ -217,8 +222,6 @@ public Node completed(org.w3c.dom.Node[] nodes) {
throw new DatabaseException(e);
} catch (TriggerException e) {
throw new DatabaseException("append aborted by listener", e);
- } finally {
- tx.abortIfIncomplete();
}
}
});
@@ -250,8 +253,8 @@ public void delete() {
} else if (parent == null) {
throw new DatabaseException("cannot delete node with no parent");
} else {
- Transaction tx = db.requireTransactionWithBroker();
- try {
+
+ try(final Transaction tx = db.requireTransactionWithBroker()) {
if (parent instanceof NodeHandle) {
tx.lockWrite(((NodeHandle) parent).getOwnerDocument());
}
@@ -263,8 +266,6 @@ public void delete() {
throw new DatabaseException(e);
} catch (TriggerException e) {
throw new DatabaseException("delete aborted by listener", e);
- } finally {
- tx.abortIfIncomplete();
}
}
}
@@ -307,8 +308,7 @@ public ElementBuilder> replace() {
return new ElementBuilder